Pentru dezvoltatori și agenții

Conectează orice magazin în câteva ore

Un API simplu, în loturi de până la 500 de obiecte, un script pentru site, webhooks semnate și un mediu de test în care nimic nu se salvează.

https://marketing.conekto.app/api/v1Primii pașiMarkdown pentru AI
Început

Primii pași

API-ul primește datele magazinului tău (clienți, produse, comenzi, evenimente) din orice platformă. Shopify și WooCommerce sunt conectate automat; restul folosesc API-ul de mai jos.

  • Creează o cheie în Setări → General → Chei API. Pentru probe, alege „Creează cheie de test”.
  • Verifică cheia cu GET /ping.
  • Trimite întâi categoriile și produsele, apoi clienții, apoi comenzile (comenzile se leagă de clienți și produse prin external_id).
  • Pune scriptul pe site pentru evenimentele de navigare (vizualizări, coș, căutări).
Verifică cheia
curl https://marketing.conekto.app/api/v1/ping \
  -H "Authorization: Bearer ck_live_…"
Răspuns
{
  "ok": true,
  "test": false,
  "shop": {
    "name": "Magazinul Meu",
    "domain": "magazin.ro",
    "platform": "custom",
    "public_key": "pk_…"
  }
}
Început

Autentificare și limite

Fiecare cerere are antetul Authorization cu cheia magazinului. Cheia identifică magazinul, deci nu trimiți niciodată un id de magazin.

RegulăValoare
AntetAuthorization: Bearer ck_live_… (sau ck_test_…)
FormatJSON, Content-Type: application/json, UTF-8
Limită de cereri600 pe minut pe cheie (în medie 10 pe secundă)
Mărimea unui lotîntre 1 și 500 de obiecte într-o cerere
Sumenumăr sau text cu punct zecimal: 349, "349.00"; se rotunjesc la 2 zecimale
DateISO 8601 cu fus orar: 2026-11-03T20:15:00+02:00
Păstrează cheia pe server. Nu o pune în codul din browser: scriptul de pe site folosește cheia publică (pk_…), care poate doar trimite evenimente.
Început

Răspunsuri și erori

Un lot nu se oprește la primul obiect greșit: obiectele bune se salvează, iar cele greșite apar în errors, cu poziția lor în listă.

Răspuns la un lot (200)
{
  "received": 2,
  "created": 1,
  "updated": 0,
  "errors": [
    {
      "index": 1,
      "message": "email: Contactul are nevoie de email sau telefon."
    }
  ]
}
CodCândCe faci
200Lotul a fost procesat (poate avea erori pe obiecte)Verifică errors; retrimite doar obiectele de la acele poziții, corectate
400Body-ul nu are forma { <listă>: [...] } sau are peste 500 de obiecteCorectează forma cererii
401Cheia lipsește, e greșită sau a fost retrasăCreează o cheie nouă din Setări
403Magazinul nu mai e activScrie-ne la suport
405Altă metodă decât POST (sau GET la /ping)Folosește metoda corectă
429Peste 600 de cereri pe minutAșteaptă câte secunde spune antetul Retry-After, apoi reia
5xxEroare la noiReîncearcă după câteva secunde, cu pauze tot mai mari

Retrimiterea aceluiași obiect e sigură: totul se salvează după external_id, deci a doua oară obiectul doar se actualizează (updated crește, nu created).

Date

Contacte

POST /contacts creează sau actualizează clienți după external_id (id-ul din platforma ta). Fiecare contact are nevoie de email sau telefon.

POST /contacts
{
  "contacts": [
    {
      "external_id": "1042",
      "email": "ana.pop@exemplu.ro",
      "phone": "0722123456",
      "first_name": "Ana",
      "last_name": "Pop",
      "city": "Cluj-Napoca",
      "county": "Cluj",
      "country": "RO",
      "email_consent": {
        "state": "subscribed",
        "updated_at": "2026-10-02T09:14:00+03:00"
      },
      "sms_consent": {
        "state": "not_subscribed"
      },
      "orders_count": 3,
      "total_spent": "742.50",
      "last_order_at": "2026-10-28T18:40:00+02:00",
      "created_at": "2025-03-11T10:00:00+02:00"
    }
  ]
}
CâmpTipDescriere
external_idtext, obligatoriuId-ul clientului în platforma ta
email / phonetextCel puțin unul. Telefonul se normalizează la formatul internațional (+40…)
first_name, last_name, city, countytextFolosite în personalizare și segmente
country2 litereRO, MD…
email_consent / sms_consentobiectstate: subscribed, not_subscribed, unsubscribed sau pending; updated_at opțional
orders_count, total_spent, last_order_atnumăr / sumă / datăIstoricul, dacă nu trimiți comenzile; altfel se calculează din comenzi
created_atdatăCând și-a făcut clientul cont
Acordul de marketing se schimbă doar dacă trimiți email_consent sau sms_consent; fără ele, contactul își păstrează starea. Un „subscribed” nu anulează o dezabonare făcută la noi decât dacă are în updated_at o dată mai nouă decât dezabonarea.
Date

Categorii

POST /categories. Trimite-le înaintea produselor; ierarhia se face cu parent_external_id.

POST /categories
{
  "categories": [
    {
      "external_id": "12",
      "name": "Încălțăminte",
      "url": "https://magazin.ro/incaltaminte"
    },
    {
      "external_id": "31",
      "name": "Sneakers",
      "url": "https://magazin.ro/incaltaminte/sneakers",
      "parent_external_id": "12"
    }
  ]
}
Date

Produse

POST /products. Produsele apar în recomandări, în blocurile de produse din emailuri și în fluxurile de stoc și preț.

POST /products
{
  "products": [
    {
      "external_id": "4421",
      "title": "Sneakers Urban Alb",
      "url": "https://magazin.ro/sneakers-urban-alb",
      "image_url": "https://magazin.ro/img/4421.jpg",
      "brand": "Urban",
      "categories": [
        "31"
      ],
      "tags": [
        "nou",
        "vara"
      ],
      "status": "active",
      "variants": [
        {
          "external_id": "4421-40",
          "sku": "URB-40",
          "title": "40",
          "price": "349.00",
          "compare_at_price": "399.00",
          "in_stock": true,
          "stock_qty": 6
        },
        {
          "external_id": "4421-41",
          "sku": "URB-41",
          "title": "41",
          "price": "349.00",
          "in_stock": false,
          "stock_qty": 0
        }
      ]
    },
    {
      "external_id": "88",
      "title": "Cutie cadou",
      "price": 19.9,
      "in_stock": true
    }
  ]
}
  • categories are external_id-urile categoriilor trimise la /categories.
  • variants: până la 250. Un produs fără variante, dar cu price sau in_stock, primește automat o variantă <external_id>#default.
  • compare_at_price mai mare decât price înseamnă reducere. Scăderea prețului pornește fluxul „Preț redus” pentru cei care au văzut produsul sau l-au pus la favorite în ultimele 30 de zile.
  • Trecerea in_stock din false în true pornește fluxul „Înapoi în stoc”, pentru aceiași vizitatori.
  • status: active, draft sau archived. Doar produsele active apar în recomandări.
Date

Comenzi

POST /orders. Comenzile calculează venitul atribuit campaniilor și fluxurilor, RFM-ul și segmentele după cumpărături.

POST /orders
{
  "orders": [
    {
      "external_id": "98123",
      "number": "#10045",
      "customer_external_id": "1042",
      "email": "ana.pop@exemplu.ro",
      "currency": "RON",
      "discount_total": "34.90",
      "shipping_total": "19.99",
      "total": "334.09",
      "financial_status": "paid",
      "fulfillment_status": "unfulfilled",
      "discount_codes": [
        "BINEAIVENIT10"
      ],
      "source_name": "web",
      "placed_at": "2026-11-03T20:15:00+02:00",
      "lines": [
        {
          "product_external_id": "4421",
          "variant_external_id": "4421-40",
          "sku": "URB-40",
          "title": "Sneakers Urban Alb",
          "variant_title": "40",
          "quantity": 1,
          "price": "349.00"
        }
      ]
    }
  ]
}
CâmpValori
financial_statuspending, paid, partially_paid, partially_refunded, refunded, voided
fulfillment_statusunfulfilled, partial, fulfilled
subtotalOpțional: dacă lipsește, e suma liniilor (preț × cantitate)
refunded_total, cancelled_atTrimite din nou comanda când se returnează sau se anulează; venitul se corectează

Comanda se leagă de client după customer_external_id, apoi după email, apoi după telefon. O comandă nouă scoate clientul din fluxurile care se opresc la comandă (de exemplu coș abandonat și produse vizitate).

Date

Evenimente de pe server

POST /events, pentru ce se întâmplă pe server (de exemplu hook-uri PHP). Pentru navigarea de pe site folosește scriptul; e mai simplu și leagă singur vizitatorul de client.

POST /events
{
  "events": [
    {
      "type": "view_product",
      "email": "ana.pop@exemplu.ro",
      "product_external_id": "4421",
      "url": "https://magazin.ro/sneakers-urban-alb"
    },
    {
      "type": "add_to_cart",
      "contact_external_id": "1042",
      "product_external_id": "4421",
      "value": "349.00",
      "props": {
        "quantity": 1
      }
    },
    {
      "type": "search",
      "vid": "v_8f2a91c0d1",
      "props": {
        "query": "sneakers albi"
      },
      "at": "2026-11-04T10:02:00+02:00"
    }
  ]
}
CâmpDescriere
typepage_view, view_product, view_category, search, add_to_cart, remove_from_cart, add_to_wishlist, remove_from_wishlist, initiate_checkout, checkout_completed, order, identify
vid / contact_external_id / email / phoneCel puțin unul, ca să știm al cui e evenimentul. vid e cookie-ul ckm_vid de pe site
product_external_id, value, urlOpționale
propsObiect liber, cel mult 4 KB (de exemplu query, quantity, cart). props.sid leagă evenimentul de sesiunea de pe site
atMomentul evenimentului; dacă lipsește, acum
Date

Ștergeri

POST /contacts/delete, /products/delete și /orders/delete primesc o listă de cel mult 500 de external_id. Fiecare ștergere rămâne în jurnalul contului.

POST /contacts/delete
{
  "external_ids": [
    "1042"
  ],
  "reason": "gdpr"
}
Răspuns
{
  "deleted": 1
}

Contactul se șterge cu tot istoricul lui. Comenzile rămân în rapoarte, fără date personale. Cu reason „gdpr” (sau „erasure”, „forget”), emailul și telefonul intră și pe lista de excludere: nu mai primesc nimic, nici dacă revin în listă. Fără motiv (de exemplu client șters din magazin), aceeași persoană se poate abona din nou.

Site

Scriptul de pe site

Un singur script pentru evenimente, formulare, pop-up-uri și notificări push. Shopify și WooCommerce îl pun singure; pe alt site îl copiezi din Setări → General.

Înainte de </head>
<script>window.ckmSettings = { k: "pk_…" };</script>
<script async src="https://marketing.conekto.app/t/s.js?k=pk_…"></script>

Scriptul numără singur paginile văzute și sesiunile. Restul evenimentelor le trimiți cu funcția ckm:

Evenimente din pagină
ckm("track", "view_product", { product_id: "4421" });
ckm("track", "add_to_cart", { product_id: "4421", props: { cart: { value: 349, items: 1, l: [{ p: "4421", q: 1, v: "4421-40" }] } } });
ckm("track", "search", { props: { query: "sneakers" } });
ckm("identify", { email: "ana.pop@exemplu.ro", src: "form" });
Setare în ckmSettingsEfect
consent: falseNu trimite nimic până nu schimbi în true (pentru bannerul de cookie-uri)
cart: {...}Coșul curent, în formatul de mai sus, pe orice pagină
dataLayer: falseOprește preluarea evenimentelor vechi din dataLayer
identify cu src „form” leagă vizitatorul de un email scris pe site (cont, contact, checkout), dar nu îl abonează. Abonarea vine doar din formularele noastre sau din acordul trimis prin API.
Site

Evenimente vechi din dataLayer

Dacă site-ul trimite deja evenimente __sm__* în dataLayer (de la platforma de marketing folosită înainte), scriptul nostru le preia singur. Nu trebuie schimbat nimic pe site.

Eveniment în dataLayerDevineObservații
__sm__set_emailidentifyemailul scris pe site; nu e acord de marketing
__sm__view_homepagepage_viewpagina se numără oricum automat
__sm__view_categoryview_categorycalea categoriei, ca în feed („A|B|C”)
__sm__view_brandpage_viewpagina de brand
__sm__view_productview_productid-ul produsului din feed
__sm__add_to_cartadd_to_cartprodus, cantitate, variantă
__sm__remove_from_cartremove_from_cartprodus, cantitate, variantă
__sm__add_to_wishlistadd_to_wishlistprodus, variantă
__sm__remove_from_wishlistremove_from_wishlistprodus, variantă
__sm__initiate_checkoutinitiate_checkoutintrarea în checkout
__sm__searchsearchtermenul căutat
__sm__orderidentifycomanda vine din platformă, API sau feed; de pe pagină luăm doar emailul

Vezi și pagina Setări → Mutare de pe altă platformă din aplicație: acolo urmărești pas cu pas ce date au ajuns.

Site

Feed de produse și de comenzi

Pentru mutare sau pentru platformele fără API: un feed XML de produse, citit zilnic, și un feed JSON de comenzi, citit pe pagini. Le configurezi în Setări → Mutare.

Feed XML de produse
<products>
  <product>
    <id>4421</id>
    <sku>URB</sku>
    <name><![CDATA[Sneakers Urban Alb]]></name>
    <url>https://magazin.ro/sneakers-urban-alb</url>
    <main_image>https://magazin.ro/img/4421.jpg</main_image>
    <category><![CDATA[Încălțăminte|Sneakers]]></category>
    <brand>Urban</brand>
    <price>399</price>
    <sale_price>349</sale_price>
    <availability>1</availability>
    <stock>6</stock>
    <variations>
      <variation><id>4421-40</id><sku>URB-40</sku><price>399</price><sale_price>349</sale_price><size>40</size><availability>1</availability><stock>6</stock></variation>
    </variations>
  </product>
</products>
  • Categoria are nivelurile despărțite de „|”; fiecare nivel devine o categorie.
  • availability: 0 = stoc epuizat, 1 sau 2 = în stoc.
  • sale_price contează doar între sale_price_start_date și sale_price_end_date, dacă sunt date (ora României).
  • Sumele pot fi „1.234,50” sau „1234.50”.
Feed JSON de comenzi (o pagină)
{
  "orders": {
    "order": [
      {
        "order_no": "10045",
        "order_status": "Livrată",
        "created_at": "2026-11-03 20:15",
        "email_address": "ana.pop@exemplu.ro",
        "phone": "0722123456",
        "firstname": "Ana",
        "lastname": "Pop",
        "discount_code": "BINEAIVENIT10",
        "discount_value": "34.90",
        "shipping": "19.99",
        "total_value": "334.09",
        "refund_value": "0",
        "products": [
          {
            "product_id": "4421",
            "name": "Sneakers Urban Alb",
            "variation_sku": "URB-40",
            "price": "399",
            "sale_price": "349",
            "quantity": 1
          }
        ]
      }
    ]
  }
}

Citim ?page=1, 2, 3… până la o pagină goală. Sunt acceptate și forma { orders: [...] } și o listă simplă.

Integrări

Webhooks

Primești pe serverul tău, în timp real, ce se întâmplă în cont. Le adaugi în Setări → Webhooks, unde vezi și ultimele livrări și poți trimite un test.

EvenimentCând
contact.subscribedUn contact s-a abonat la email sau SMS (formular, pop-up, confirmare).
contact.unsubscribedUn contact s-a dezabonat sau adresa a fost curățată.
form.submittedUn formular sau pop-up a fost trimis, cu câmpurile completate.
campaign.sentO campanie a terminat trimiterea, cu numărul de destinatari.
transactional.sentUn email sau SMS din API ori SMTP a plecat la furnizor.
transactional.deliveredFurnizorul confirmă că mesajul a ajuns la destinatar.
transactional.bouncedAdresa sau numărul a respins mesajul (bounce).
transactional.complainedDestinatarul a marcat emailul ca spam.
transactional.failedMesajul nu a plecat: adresă exclusă, mod de test, credit sau eroare.
Corpul cererii (POST, JSON)
{
  "id": "whd_…",
  "event": "contact.subscribed",
  "createdAt": "2026-11-04T08:12:31.000Z",
  "shop": "magazin.ro",
  "data": {
    "id": "…",
    "email": "ana.pop@exemplu.ro",
    "emailStatus": "SUBSCRIBED",
    "smsStatus": "NOT_SUBSCRIBED",
    "whatsappStatus": "NOT_SUBSCRIBED",
    "tags": [],
    "source": "form"
  }
}
AntetConținut
X-Conekto-EventNumele evenimentului
X-Conekto-DeliveryId-ul livrării; îl folosești ca să nu procesezi de două ori
X-Conekto-TimestampSecunde de la 1970
X-Conekto-Signaturesha256= + HMAC SHA-256 cu secretul webhook-ului, peste <timestamp>.<corp>
Verificarea semnăturii (PHP)
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_CONEKTO_TIMESTAMP'];
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $body, getenv('CONEKTO_WEBHOOK_SECRET'));
if (!hash_equals($expected, $_SERVER['HTTP_X_CONEKTO_SIGNATURE']) || abs(time() - (int)$ts) > 300) {
  http_response_code(401); exit;
}
  • Răspunde cu un cod 2xx în cel mult 10 secunde; altfel livrarea se reia de până la 5 ori, la intervale tot mai mari.
  • După 50 de eșecuri la rând, webhook-ul se oprește singur și îl repornești din Setări.
  • Doar adrese https publice; istoricul livrărilor se păstrează 30 de zile.
Integrări

Mediu de test

Faci integrarea fără ca datele de probă să ajungă în contacte, comenzi sau rapoarte.

  • Cheile ck_test_… răspund exact ca cele reale (aceleași validări, aceleași erori pe obiecte), dar nu salvează și nu șterg nimic. Răspunsul are "test": true.
  • Domeniile de test (Setări → Mediu de test): scriptul pus pe staging trimite evenimente care nu se salvează și nu pornesc automatizări.
  • Ce primim de la cheile și domeniile de test apare în jurnalul din aceeași pagină, în câteva secunde (ultimele 100 de cereri, 24 de ore).
Un contact trimis cu cheia de test
curl -X POST https://marketing.conekto.app/api/v1/contacts \
  -H "Authorization: Bearer ck_test_…" \
  -H "Content-Type: application/json" \
  -d '{"contacts":[{"external_id":"42","email":"ion@exemplu.ro","email_consent":{"state":"subscribed"}}]}'
Răspuns
{
  "received": 1,
  "created": 1,
  "updated": 0,
  "errors": [],
  "test": true,
  "note": "Cheie de test: datele au fost verificate, dar nu au fost salvate."
}
Integrări

Documentația pentru asistenți AI

Toată documentația, ca un singur fișier text, pentru Claude, ChatGPT sau Cursor.

  • /llms.txt: rezumatul și legăturile, după standardul llms.txt.
  • /dezvoltatori.md: toată documentația într-un singur fișier Markdown.
  • Conectorul Claude (MCP) din aplicație: Claude lucrează direct în cont (campanii, segmente, rapoarte).
Altele

Ce s-a schimbat

Schimbările din API, script și webhooks. Orice schimbare care cere modificări în integrarea ta apare aici înainte s-o facem.

  1. Mediu de test și mutare de pe altă platformă
    • Chei API de test (ck_test_…): aceleași validări, nimic salvat; răspunsul are „test”: true.
    • Domenii de test pentru script: evenimentele de pe staging nu se salvează și apar în jurnalul de test.
    • Scriptul preia evenimentele vechi din dataLayer (__sm__*), fără schimbări pe site.
    • Import din feed XML de produse (zilnic) și feed JSON de comenzi, pe pagini.
  2. Webhooks
    • 4 evenimente: abonare, dezabonare, formular trimis, campanie trimisă. Semnătură HMAC SHA-256, 5 reîncercări.
  3. API v1
    • Contacte, produse, categorii, comenzi, evenimente și ștergeri, în loturi de până la 500 de obiecte.
Ai nevoie de ajutor cu integrarea?

Scrie-ne cu exemplul de cerere și răspunsul primit. Te ajutăm să găsești problema.

Scrie-ne