API-ul BB123 reflectă structura reală a datelor: clientul este persoana, iar lead-ul este intenția lui de cumpărare într-un pipeline anume. Un client poate avea mai multe lead-uri simultan.
URL de bază
https://bb123.lovable.app/api/public/v1Autentificare
Fiecare cerere trimite cheia API în header. Cheile se creează în Setări → API și pot avea pipeline, etapă, sursă și consultant impliciți, folosiți când nu trimiți acele câmpuri.
X-API-Key: CHEIA_TA
Content-Type: application/jsonConvenții
{ "ok": true, "data": ... }. Listele adaugă total, page și limit (limit între 1 și 200, implicit 50).{ "ok": false, "error": "...", "code": "...", "details"?: [...] }, unde details este un array<string> cu problemele concrete.date (YYYY-MM-DD) în fusul Europe/Chișinău; cele cu oră sunt datetime ISO 8601 (UTC).PATCH/PUT/POST de actualizare, câmpul absent rămâne neschimbat, iar null șterge valoarea.GET, POST, PUT, PATCH, DELETE, OPTIONS. Limită: 60 de cereri pe minut per cheie.[[email]], {{phone}}, %nume%) sunt ignorate: câmpul rămâne gol, iar cererea primește un warnings în răspuns și un avertisment în Setări → API → Loguri API.Formatele câmpurilor
| string | Text UTF-8. Se elimină spațiile de la capete. Fiecare câmp are lungime maximă. |
| integer | Număr întreg, fără zecimale (ex. `duration_minutes: 25`). |
| number | Număr cu zecimale, separator punct (ex. `amount: 1250.5`). Se acceptă și ca text numeric („1250.5”) și se convertește automat. |
| boolean | `true` / `false`. Din formulare se acceptă și „true” / „1”. |
| uuid | Identificator UUID v4, ex. `3f1b9c2e-8a41-4d76-9f0a-2b7c5e6d1a33`. |
| date | Doar data, `YYYY-MM-DD`, interpretată în fusul Europe/Chișinău. |
| datetime | Data și ora ISO 8601 cu fus, ex. `2026-09-03T09:30:00.000Z`. |
| enum | Una din valorile listate explicit; orice altă valoare întoarce 400. |
| object | Obiect JSON imbricat; câmpurile lui sunt documentate separat. |
| array<T> | Listă JSON de elemente de tipul `T` (ex. `array<object>`). |
| null | Un câmp marcat „poate fi null” acceptă `null`. La `PATCH`, `null` șterge valoarea, iar câmpul absent o lasă neschimbată. |
Exemplu complet (creare lead + interacțiune)
BASE="https://bb123.lovable.app/api/public/v1"
# 1. Creează clientul și lead-ul într-un singur apel
LEAD=$(curl -s -X POST "$BASE/leads" \
-H "X-API-Key: CHEIA_TA" -H "Content-Type: application/json" \
-d '{"client":{"name":"Maria Popescu","phone":"+37360000000"},"source":"Formular website","warmth":"warm"}')
LEAD_ID=$(echo "$LEAD" | grep -o '"id":"[^"]*' | head -1 | cut -d'"' -f4)
# 2. Notează rezultatul primului apel
curl -s -X POST "$BASE/interactions" \
-H "X-API-Key: CHEIA_TA" -H "Content-Type: application/json" \
-d '{"lead_id":"'"$LEAD_ID"'","type":"Apel de calificare","duration_minutes":25,
"outcome":"Programat pentru consultație","fields":{"Interes principal":"Somn de noapte"}}'
# 3. Mută lead-ul în etapa următoare
curl -s -X POST "$BASE/leads/$LEAD_ID/stage" \
-H "X-API-Key: CHEIA_TA" -H "Content-Type: application/json" \
-d '{"stage":"Apel 1"}'Endpointuri de citire pentru a afla ce valori poți trimite: pipeline-uri și etapele lor, surse, consultanți, produse și tipuri de interacțiune. Oriunde un câmp acceptă „id sau nume”, poți folosi numele exact așa cum apare aici. Toate câmpurile din API sunt în engleză.
/api/public/v1/pipelinesPipeline-uri și etape
Lista pipeline-urilor active, fiecare cu etapele sale în ordine, inclusiv marcajele de câștigat/pierdut.
Exemplu de cerere (cURL)
curl -X GET "$BASE/pipelines" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{
"id": "3f1b9c2e-8a41-4d76-9f0a-2b7c5e6d1a33",
"name": "Vânzări consultații",
"description": "Fluxul principal de vânzare",
"color": "#5B8DB8",
"position": 1,
"is_default": true,
"stages": [
{ "id": "8c2d0f11-55a7-4f2b-9c31-6d0be1f9a742", "name": "Lead nou", "position": 1,
"color": "#DCEAF7", "is_won": false, "is_lost": false },
{ "id": "b41e7a90-2c58-4f0d-8a17-9e3d5c6b2f08", "name": "Apel 1", "position": 2,
"color": "#DCEAF7", "is_won": false, "is_lost": false },
{ "id": "d9a3c710-64bf-4e21-b8f5-1a2c3d4e5f60", "name": "Vândut", "position": 3,
"color": "#A7D8B0", "is_won": true, "is_lost": false }
]
}
]
}Câmpurile răspunsului
| id | uuid | Id-ul pipeline-ului. |
| name | string | Numele pipeline-ului. |
| description | string | null | Descriere internă. |
| color | string | null | Cod HEX de culoare. |
| position | integer | Ordinea de afișare. |
| is_default | boolean | Pipeline-ul folosit când nu trimiți `pipeline`. |
| stages | array<object> | Etapele active, în ordinea `position`. |
| stages[].is_won | boolean | Etapă de câștig. |
| stages[].is_lost | boolean | Etapă de pierdere. |
Erori posibile
{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/sourcesSurse de lead-uri
Sursele active configurate în aplicație. Dacă trimiți o sursă nouă la creare, ea se adaugă automat în listă exact cu numele trimis.
Exemplu de cerere (cURL)
curl -X GET "$BASE/sources" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{ "id": "5e7f8a90-1b2c-4d3e-8f90-a1b2c3d4e5f6", "name": "Formular website", "position": 1 },
{ "id": "6f8a9b01-2c3d-4e5f-9a01-b2c3d4e5f607", "name": "Instagram DM", "position": 2 }
]
}Câmpurile răspunsului
| id | uuid | Id-ul sursei. |
| name | string | Numele sursei (valoarea de trimis în `source`). |
| position | integer | Ordinea în listă. |
Erori posibile
{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/consultantsConsultanți
Utilizatorii activi și rolul lor; folosește `id` pentru câmpul `consultant_id`.
Exemplu de cerere (cURL)
curl -X GET "$BASE/consultants" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{ "id": "a1b2c3d4-e5f6-4708-9a1b-2c3d4e5f6071", "name": "Ana Rusu", "role": "consultant" },
{ "id": "b2c3d4e5-f607-4819-a2b3-c4d5e6f70812", "name": "Vadim Ciobanu", "role": "admin" }
]
}Câmpurile răspunsului
| id | uuid | Id-ul utilizatorului (`consultant_id`). |
| name | string | Numele complet. |
| role | enum("admin"|"consultant") | Rolul în aplicație. |
Erori posibile
{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/productsCatalog de produse
Produsele nearhivate, cu preț, monedă, tip, livrare și intervalul de vârstă recomandat (în luni).
Exemplu de cerere (cURL)
curl -X GET "$BASE/products" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{
"id": "c3d4e5f6-0718-4920-b3c4-d5e6f7081923",
"name": "Curs Montessori 0-6 luni",
"description": "Curs video cu 12 module",
"type": "curs",
"category": "Montessori",
"delivery_type": "digital",
"price": 890,
"currency": "MDL",
"is_free": false,
"lead_magnet": false,
"age_min_months": 0,
"age_max_months": 6,
"is_active": true
}
]
}Câmpurile răspunsului
| id | uuid | Id-ul produsului. |
| name | string | Denumirea (acceptată și în câmpul `product`). |
| description | string | null | Descriere. |
| type | string | Tipul intern de produs (ex. „curs”, „consultație”). |
| category | string | null | Categoria. |
| delivery_type | enum("digital"|"physical") | null | Mod de livrare. |
| price | number | Prețul unitar. |
| currency | string | Moneda prețului. |
| is_free | boolean | Produs gratuit. |
| lead_magnet | boolean | Produs folosit ca lead magnet. |
| age_min_months | integer | null | Vârsta minimă recomandată, luni. |
| age_max_months | integer | null | Vârsta maximă recomandată, luni. |
| is_active | boolean | Produs activ pentru vânzare. |
Erori posibile
{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/interaction-typesTipuri de interacțiune
Tipurile active și câmpurile personalizate ale fiecăruia. Le folosești la `POST /interactions`: cheia din `fields` poate fi `id`-ul câmpului sau eticheta lui exactă.
Exemplu de cerere (cURL)
curl -X GET "$BASE/interaction-types" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{
"id": "d4e5f607-1829-4a31-c4d5-e6f708192a34",
"name": "Apel de calificare",
"description": "Primul apel cu părintele",
"stage": { "id": "b41e7a90-2c58-4f0d-8a17-9e3d5c6b2f08", "name": "Apel 1",
"pipeline_id": "3f1b9c2e-8a41-4d76-9f0a-2b7c5e6d1a33" },
"fields": [
{ "id": "e5f60718-2a3b-4b42-d5e6-f708192a3b45", "label": "Interes principal",
"description": "Ce îl preocupă cel mai mult", "type": "text", "options": null, "is_required": true },
{ "id": "f6071829-3b4c-4c53-e6f7-08192a3b4c56", "label": "Nr. treziri pe noapte",
"description": null, "type": "number", "options": null, "is_required": false },
{ "id": "07182930-4c5d-4d64-f708-192a3b4c5d67", "label": "Rutina actuală",
"description": null, "type": "select", "options": ["Adoarme în brațe", "Adoarme singur"],
"is_required": false }
]
}
]
}Câmpurile răspunsului
| id | uuid | Id-ul tipului (valoare pentru `type`). |
| name | string | Numele tipului (acceptat și el în `type`). |
| description | string | null | Descriere. |
| stage | object | null | `{ id, name, pipeline_id }` — etapa asociată. |
| fields | array<object> | Câmpurile personalizate ale tipului. |
| fields[].id | uuid | Cheia recomandată în obiectul `fields`. |
| fields[].label | string | Eticheta afișată; acceptată și ca cheie. |
| fields[].type | enum("text"|"textarea"|"number"|"checkbox"|"select"|"date") | Formatul valorii așteptate. |
| fields[].options | array<string> | null | Opțiunile pentru `select`. |
| fields[].is_required | boolean | Dacă lipsește, cererea întoarce 400. |
Erori posibile
{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }Clientul este persoana (părintele). Datele de contact și copiii aparțin clientului, nu lead-ului. Un client poate avea oricâte lead-uri.
/api/public/v1/clientsCaută / listează clienți
Căutare după telefon, email sau nume, cu paginare. Fiecare client vine cu copiii și lead-urile lui.
Parametri query
| phone | string | Potrivire exactă pe telefon. |
| string | Potrivire exactă pe email. | |
| name | string | Potrivire parțială, fără majuscule/minuscule, în nume. |
| limit | integer | Elemente pe pagină.(1–200, implicit 50) |
| page | integer | Pagina cerută.(≥ 1, implicit 1) |
Exemplu de cerere (cURL)
curl -X GET "$BASE/clients?phone=%2B37360000000&limit=20&page=1" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{
"id": "11111111-2222-4333-8444-555555555555",
"name": "Maria Popescu",
"phone": "+37360000000",
"email": "maria@exemplu.md",
"telegram": null,
"instagram": null,
"messenger": null,
"tiktok": null,
"notes": null,
"children": [
{ "id": "66666666-7777-4888-8999-aaaaaaaaaaaa", "name": "Ana", "age": 14,
"age_unit": "weeks", "age_declared_on": "2026-09-03", "notes": null }
],
"leads": [
{ "id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff", "client_id": "11111111-2222-4333-8444-555555555555",
"title": null,
"pipeline": { "id": "3f1b9c2e-8a41-4d76-9f0a-2b7c5e6d1a33", "name": "Vânzări consultații" },
"stage": { "id": "8c2d0f11-55a7-4f2b-9c31-6d0be1f9a742", "name": "Lead nou" },
"source": "Formular website", "warmth": "warm", "consultant_id": null,
"lead_date": "2026-09-03", "status": "open", "notes": null, "closed_at": null,
"created_at": "2026-09-03T09:30:00.000Z", "updated_at": "2026-09-03T09:30:00.000Z" }
],
"created_at": "2026-09-03T09:30:00.000Z",
"updated_at": "2026-09-03T09:30:00.000Z"
}
],
"total": 1,
"page": 1,
"limit": 20
}Câmpurile răspunsului
| ok | boolean | `true` la succes. |
| data | array<object> | Elementele paginii curente. |
| total | integer | Numărul total de rânduri care corespund filtrelor. |
| page | integer | Pagina returnată (de la 1). |
| limit | integer | Numărul de elemente pe pagină. |
| data[].id | uuid | Id-ul clientului. |
| data[].name | string | Numele părintelui. |
| data[].phone | string | null | Telefon. |
| data[].email | string | null | Email. |
| data[].telegram | string | null | Contact Telegram. |
| data[].instagram | string | null | Contact Instagram. |
| data[].messenger | string | null | Contact Messenger. |
| data[].tiktok | string | null | Contact TikTok. |
| data[].notes | string | null | Notițele persoanei. |
| data[].children | array<object> | Copiii clientului (vezi tabelul copiilor). |
| data[].leads | array<object> | Lead-urile clientului, cele mai recente primele. |
| data[].created_at | datetime | Momentul creării. |
| data[].updated_at | datetime | Ultima modificare. |
Erori posibile
{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/clientsCreează un client
Creează clientul, opțional cu copii. Dacă `dedupe` găsește un client existent, îl întoarce cu `exists: true` și cod 200, fără să creeze duplicat; altfel răspunde 201 cu `exists: false`.
Câmpurile cererii
| name* | string | Numele părintelui.(1–160 caractere) |
| phone | string | Telefon de contact.(max 60) |
| string | Email de contact.(max 160) | |
| telegram | string | Contact Telegram.(max 120) |
| string | Contact Instagram.(max 120) | |
| messenger | string | Contact Messenger.(max 120) |
| tiktok | string | Contact TikTok.(max 120) |
| notes | string | Note libere despre persoană.(max 4000) |
| dedupe | enum("phone"|"email"|"both"|"none") | Cum se caută duplicatele înainte de creare.(implicit „both”) |
| children | array<object> | Copiii clientului. Vârsta se salvează împreună cu data de azi (Chișinău).(max 10 elemente) |
| children[].name | string | Numele copilului.(max 120) |
| children[].age | number | Vârsta declarată.(0–400) |
| children[].age_unit | enum("weeks"|"months"|"years") | Unitatea vârstei.(implicit „months”) |
| children[].notes | string | Note despre copil.(max 2000) |
Exemplu de corp al cererii (JSON)
{
"name": "Maria Popescu",
"phone": "+37360000000",
"email": "maria@exemplu.md",
"telegram": "@mariap",
"notes": "A scris pe Instagram",
"dedupe": "both",
"children": [
{ "name": "Ana", "age": 14, "age_unit": "weeks", "notes": "Se trezește des" }
]
}Exemplu de cerere (cURL)
curl -X POST "$BASE/clients" \
-H "X-API-Key: CHEIA_TA" \
-H "Content-Type: application/json" \
-d '{
"name": "Maria Popescu",
"phone": "+37360000000",
"email": "maria@exemplu.md",
"children": [{ "name": "Ana", "age": 14, "age_unit": "weeks" }]
}'Exemplu de răspuns
{
"ok": true,
"data": {
"exists": false,
"client": {
"id": "11111111-2222-4333-8444-555555555555",
"name": "Maria Popescu",
"phone": "+37360000000",
"email": "maria@exemplu.md",
"telegram": "@mariap",
"instagram": null,
"messenger": null,
"tiktok": null,
"notes": "A scris pe Instagram",
"children": [
{ "id": "66666666-7777-4888-8999-aaaaaaaaaaaa", "name": "Ana", "age": 14,
"age_unit": "weeks", "age_declared_on": "2026-09-03", "notes": "Se trezește des" }
],
"leads": [],
"created_at": "2026-09-03T09:30:00.000Z",
"updated_at": "2026-09-03T09:30:00.000Z"
}
}
}Câmpurile răspunsului
| exists | boolean | `true` dacă s-a găsit un client existent prin dedupe. |
| client | object | Clientul complet (vezi câmpurile mai jos). |
| client.id | uuid | Id-ul clientului. |
| client.name | string | Numele părintelui. |
| client.phone | string | null | Telefon. |
| client.email | string | null | Email. |
| client.telegram | string | null | Contact Telegram. |
| client.instagram | string | null | Contact Instagram. |
| client.messenger | string | null | Contact Messenger. |
| client.tiktok | string | null | Contact TikTok. |
| client.notes | string | null | Notițele persoanei. |
| client.children | array<object> | Copiii clientului (vezi tabelul copiilor). |
| client.leads | array<object> | Lead-urile clientului, cele mai recente primele. |
| client.created_at | datetime | Momentul creării. |
| client.updated_at | datetime | Ultima modificare. |
Erori posibile
{
"ok": false,
"error": "Date invalide.",
"code": "invalid_data",
"details": ["name: Required", "phone: String must contain at most 60 character(s)"]
}{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/clients/{id}Fișa completă a clientului
Clientul cu toți copiii și lead-urile lui, plus ultimele 20 de interacțiuni și toate vânzările înregistrate.
Exemplu de cerere (cURL)
curl -X GET "$BASE/clients/11111111-2222-4333-8444-555555555555" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": {
"client": {
"id": "11111111-2222-4333-8444-555555555555",
"name": "Maria Popescu",
"phone": "+37360000000",
"email": "maria@exemplu.md",
"telegram": null, "instagram": null, "messenger": null, "tiktok": null,
"notes": null,
"children": [ { "id": "66666666-7777-4888-8999-aaaaaaaaaaaa", "name": "Ana", "age": 14,
"age_unit": "weeks", "age_declared_on": "2026-09-03", "notes": null } ],
"leads": [ { "id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff", "status": "open", "...": "..." } ],
"created_at": "2026-09-03T09:30:00.000Z",
"updated_at": "2026-09-03T09:30:00.000Z"
},
"interactions": [
{ "id": "22222222-3333-4444-8555-666666666666",
"client_id": "11111111-2222-4333-8444-555555555555",
"lead_id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"type": { "id": "d4e5f607-1829-4a31-c4d5-e6f708192a34", "name": "Apel de calificare" },
"label": "Apel de calificare",
"stage": { "id": "b41e7a90-2c58-4f0d-8a17-9e3d5c6b2f08", "name": "Apel 1" },
"date": "2026-09-03T10:15:00.000Z", "duration_minutes": 25,
"outcome": "Programat pentru consultație", "notes": null,
"fields": { "e5f60718-2a3b-4b42-d5e6-f708192a3b45": "Somn de noapte" },
"created_at": "2026-09-03T10:16:00.000Z" }
],
"sales": [
{ "id": "33333333-4444-4555-8666-777777777777",
"client_id": "11111111-2222-4333-8444-555555555555",
"lead_id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"product": { "id": "c3d4e5f6-0718-4920-b3c4-d5e6f7081923", "name": "Curs Montessori 0-6 luni" },
"produs_nume": "Curs Montessori 0-6 luni",
"quantity": 1, "unit": "buc", "amount": 890, "currency": "MDL",
"status": "paid", "date": "2026-09-03", "consultant_id": null, "notes": null,
"created_at": "2026-09-03T11:00:00.000Z" }
]
}
}Câmpurile răspunsului
| client | object | Clientul complet, cu `children` și `leads`. |
| interactions | array<object> | Ultimele 20 de interacțiuni, cele mai noi primele. |
| sales | array<object> | Vânzările clientului, cele mai noi primele. |
Erori posibile
{ "ok": false, "error": "ID invalid.", "code": "invalid_data" }{ "ok": false, "error": "Client not_found.", "code": "not_found" }{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/clients/{id}Actualizează clientul
Se modifică doar câmpurile trimise; `null` șterge valoarea, iar câmpul absent rămâne neschimbat. `POST` pe aceeași cale are exact același comportament (update parțial).
Câmpurile cererii
| name | string | Numele părintelui.(1–160) |
| phone | string | null | Telefon.(max 60) |
| string | null | Email.(max 160) | |
| telegram | string | null | Telegram.(max 120) |
| string | null | Instagram.(max 120) | |
| messenger | string | null | Messenger.(max 120) |
| tiktok | string | null | TikTok.(max 120) |
| notes | string | null | Notițele persoanei.(max 4000) |
| notes_mode | enum("replace"|"append") | „append” adaugă la notițele existente, cu separator datat (ora Chișinău).(implicit „replace”) |
Exemplu de corp al cererii (JSON)
{
"phone": "+37360000001",
"instagram": null,
"notes": "A confirmat programarea",
"notes_mode": "append"
}Exemplu de cerere (cURL)
curl -X PATCH "$BASE/clients/11111111-2222-4333-8444-555555555555" \
-H "X-API-Key: CHEIA_TA" \
-H "Content-Type: application/json" \
-d '{ "phone": "+37360000001", "notes": "A confirmat programarea", "notes_mode": "append" }'Exemplu de răspuns
{
"ok": true,
"data": {
"client": {
"id": "11111111-2222-4333-8444-555555555555",
"name": "Maria Popescu",
"phone": "+37360000001",
"instagram": null,
"notes": "Prima notă\n\n— 03.09.2026, 12:30 —\nA confirmat programarea",
"children": [],
"leads": [],
"created_at": "2026-09-03T09:30:00.000Z",
"updated_at": "2026-09-03T09:35:00.000Z"
}
}
}Câmpurile răspunsului
| client | object | Clientul complet după actualizare. |
Erori posibile
{ "ok": false, "error": "ID invalid.", "code": "invalid_data" }{ "ok": false, "error": "Client not_found.", "code": "not_found" }{
"ok": false,
"error": "Date invalide.",
"code": "invalid_data",
"details": ["name: Required", "phone: String must contain at most 60 character(s)"]
}{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/clients/{id}/childrenListează copiii clientului
Copiii în ordinea adăugării, cu vârsta declarată și data declarării.
Exemplu de cerere (cURL)
curl -X GET "$BASE/clients/11111111-2222-4333-8444-555555555555/children" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{ "id": "66666666-7777-4888-8999-aaaaaaaaaaaa", "name": "Ana", "age": 14,
"age_unit": "weeks", "age_declared_on": "2026-09-03", "notes": null }
]
}Câmpurile răspunsului
| data[].id | uuid | Id-ul copilului. |
| data[].name | string | null | Numele copilului. |
| data[].age | number | null | Vârsta declarată, în unitatea din `age_unit`. |
| data[].age_unit | enum("weeks"|"months"|"years") | Unitatea vârstei declarate. |
| data[].age_declared_on | date | Data la care s-a declarat vârsta (baza estimării ulterioare). |
| data[].notes | string | null | Note despre copil. |
Erori posibile
{ "ok": false, "error": "ID invalid.", "code": "invalid_data" }{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/clients/{id}/childrenAdaugă un copil
Vârsta se stochează împreună cu data declarării, ca vârsta actuală să poată fi estimată ulterior.
Câmpurile cererii
| name | string | null | Numele copilului.(max 120) |
| age | number | null | Vârsta declarată.(0–400) |
| age_unit | enum("weeks"|"months"|"years") | Unitatea vârstei.(implicit „months”) |
| age_declared_on | date | Data la care a fost declarată vârsta.(implicit azi (Chișinău)) |
| notes | string | null | Note despre copil.(max 2000) |
Exemplu de corp al cererii (JSON)
{ "name": "Ana", "age": 4, "age_unit": "months", "age_declared_on": "2026-09-01" }Exemplu de cerere (cURL)
curl -X POST "$BASE/clients/11111111-2222-4333-8444-555555555555/children" \
-H "X-API-Key: CHEIA_TA" \
-H "Content-Type: application/json" \
-d '{ "name": "Ana", "age": 4, "age_unit": "months" }'Exemplu de răspuns
{
"ok": true,
"data": { "id": "66666666-7777-4888-8999-aaaaaaaaaaaa", "name": "Ana", "age": 4,
"age_unit": "months", "age_declared_on": "2026-09-01", "notes": null }
}Câmpurile răspunsului
| id | uuid | Id-ul copilului. |
| name | string | null | Numele copilului. |
| age | number | null | Vârsta declarată, în unitatea din `age_unit`. |
| age_unit | enum("weeks"|"months"|"years") | Unitatea vârstei declarate. |
| age_declared_on | date | Data la care s-a declarat vârsta (baza estimării ulterioare). |
| notes | string | null | Note despre copil. |
Erori posibile
{ "ok": false, "error": "ID invalid.", "code": "invalid_data" }{ "ok": false, "error": "Client not_found.", "code": "not_found" }{
"ok": false,
"error": "Date invalide.",
"code": "invalid_data",
"details": ["name: Required", "phone: String must contain at most 60 character(s)"]
}{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/clients/{id}/childrenActualizează un copil
Trimite `child_id` pentru a preciza copilul; fără el se actualizează primul copil adăugat. Dacă trimiți `age` fără `age_declared_on`, data declarării devine ziua de azi.
Câmpurile cererii
| child_id | uuid | Copilul de modificat.(implicit primul copil) |
| name | string | null | Numele copilului. |
| age | number | null | Vârsta declarată.(0–400) |
| age_unit | enum("weeks"|"months"|"years") | Unitatea vârstei. |
| age_declared_on | date | Data declarării. |
| notes | string | null | Note despre copil. |
Exemplu de corp al cererii (JSON)
{ "child_id": "66666666-7777-4888-8999-aaaaaaaaaaaa", "age": 5, "age_unit": "months" }Exemplu de cerere (cURL)
curl -X PATCH "$BASE/clients/11111111-2222-4333-8444-555555555555/children" \
-H "X-API-Key: CHEIA_TA" \
-H "Content-Type: application/json" \
-d '{ "child_id": "66666666-7777-4888-8999-aaaaaaaaaaaa", "age": 5 }'Exemplu de răspuns
{
"ok": true,
"data": { "id": "66666666-7777-4888-8999-aaaaaaaaaaaa", "name": "Ana", "age": 5,
"age_unit": "months", "age_declared_on": "2026-09-03", "notes": null }
}Câmpurile răspunsului
| id | uuid | Id-ul copilului. |
| name | string | null | Numele copilului. |
| age | number | null | Vârsta declarată, în unitatea din `age_unit`. |
| age_unit | enum("weeks"|"months"|"years") | Unitatea vârstei declarate. |
| age_declared_on | date | Data la care s-a declarat vârsta (baza estimării ulterioare). |
| notes | string | null | Note despre copil. |
Erori posibile
{ "ok": false, "error": "ID invalid.", "code": "invalid_data" }{ "ok": false, "error": "Copil not_found.", "code": "not_found" }{
"ok": false,
"error": "Date invalide.",
"code": "invalid_data",
"details": ["name: Required", "phone: String must contain at most 60 character(s)"]
}{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/clients/{id}/childrenȘterge un copil
Copilul se indică prin parametrul de query `child_id`.
Parametri query
| child_id* | uuid | Copilul de șters. |
Exemplu de cerere (cURL)
curl -X DELETE "$BASE/clients/11111111-2222-4333-8444-555555555555/children?child_id=66666666-7777-4888-8999-aaaaaaaaaaaa" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{ "ok": true, "data": { "deleted": true } }Câmpurile răspunsului
| deleted | boolean | `true` dacă ștergerea a reușit. |
Erori posibile
{ "ok": false, "error": "Lipsește parametrul child_id.", "code": "invalid_data" }{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }Lead-ul este intenția de cumpărare: aparține unui client și trăiește într-un pipeline, pe o etapă. Același client poate avea lead-uri în pipeline-uri diferite.
/api/public/v1/leadsListează lead-uri
Filtre pe pipeline, etapă, status, consultant, client și interval de date. Fiecare lead include un rezumat al clientului.
Parametri query
| pipeline | string | Id sau nume de pipeline (fără diferență de majuscule). |
| stage | uuid | Id de etapă. |
| status | enum("open"|"won"|"lost") | Starea lead-ului. |
| consultant_id | uuid | Consultantul atribuit. |
| client_id | uuid | Toate lead-urile unui client. |
| from | date | Data lead-ului ≥ valoare.(YYYY-MM-DD) |
| to | date | Data lead-ului ≤ valoare.(YYYY-MM-DD) |
| limit | integer | Elemente pe pagină.(1–200, implicit 50) |
| page | integer | Pagina cerută.(≥ 1, implicit 1) |
Exemplu de cerere (cURL)
curl -X GET "$BASE/leads?status=open&pipeline=Vânzări%20consultații&limit=20" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{
"id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"client_id": "11111111-2222-4333-8444-555555555555",
"title": null,
"pipeline": { "id": "3f1b9c2e-8a41-4d76-9f0a-2b7c5e6d1a33", "name": "Vânzări consultații" },
"stage": { "id": "8c2d0f11-55a7-4f2b-9c31-6d0be1f9a742", "name": "Lead nou" },
"source": "Formular website",
"warmth": "warm",
"consultant_id": null,
"lead_date": "2026-09-03",
"status": "open",
"notes": null,
"closed_at": null,
"created_at": "2026-09-03T09:30:00.000Z",
"updated_at": "2026-09-03T09:30:00.000Z",
"client": { "id": "11111111-2222-4333-8444-555555555555", "name": "Maria Popescu",
"phone": "+37360000000", "email": "maria@exemplu.md" }
}
],
"total": 42,
"page": 1,
"limit": 20
}Câmpurile răspunsului
| ok | boolean | `true` la succes. |
| data | array<object> | Elementele paginii curente. |
| total | integer | Numărul total de rânduri care corespund filtrelor. |
| page | integer | Pagina returnată (de la 1). |
| limit | integer | Numărul de elemente pe pagină. |
| data[].id | uuid | Id-ul lead-ului. |
| data[].client_id | uuid | Clientul (persoana) căruia aparține lead-ul. |
| data[].title | string | null | Denumirea scurtă a lead-ului. |
| data[].pipeline | object | null | `{ id: uuid, name: string }`. |
| data[].stage | object | null | `{ id: uuid, name: string }` — etapa curentă. |
| data[].source | string | null | Numele sursei, exact cum e în lista de surse. |
| data[].warmth | enum("cold"|"warm"|"hot") | null | Gradul de interes. |
| data[].consultant_id | uuid | null | Consultantul atribuit. |
| data[].lead_date | date | Data lead-ului. |
| data[].status | enum("open"|"won"|"lost") | Starea lead-ului. |
| data[].notes | string | null | Notițele lead-ului. |
| data[].closed_at | datetime | null | Momentul închiderii (won/lost). |
| data[].created_at | datetime | Momentul creării. |
| data[].updated_at | datetime | null | Ultima modificare. |
| data[].client | object | null | `{ id, name, phone, email }` — rezumatul clientului. |
Erori posibile
{ "ok": false, "error": "Pipeline „Vanzari” nu există sau nu e is_active.",
"code": "invalid_data", "details": ["Vânzări consultații", "Recuperare"] }{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/leadsCreează un lead
Trimite `client_id` pentru un client existent, sau obiectul `client` pentru a-l crea/regăsi într-un singur apel. Pipeline-ul și etapa se pot da prin id sau nume; dacă lipsesc, se folosesc valorile implicite ale cheii API, apoi pipeline-ul implicit și prima etapă a lui. Schimbarea etapei se scrie automat în istoric.
Câmpurile cererii
| client_id | uuid | Clientul existent. Obligatoriu dacă nu trimiți `client`. |
| client | object | Client nou sau regăsit: `name` (obligatoriu), `phone`, `email`, `telegram`, `instagram`, `messenger`, `tiktok`, `notes`, `dedupe`. |
| pipeline | string | Id sau nume de pipeline.(implicit: cheia API, apoi pipeline-ul implicit) |
| stage | string | Id sau nume de etapă din pipeline-ul respectiv.(implicit prima etapă) |
| title | string | Denumire scurtă a lead-ului.(max 200) |
| source | string | Sursa; se adaugă automat în listă dacă e nouă.(max 120) |
| warmth | enum("cold"|"warm"|"hot") | Gradul de interes. |
| consultant_id | uuid | null | Consultantul atribuit.(implicit consultantul cheii) |
| lead_date | date | Data lead-ului.(YYYY-MM-DD, implicit azi (Chișinău)) |
| notes | string | Note libere ale lead-ului.(max 4000) |
| child | object | Copil nou al clientului: `{ name, age, age_unit }`. |
| extra | object | Orice câmpuri suplimentare; se adaugă ca text („cheie: valoare”) în notițele lead-ului. |
Exemplu de corp al cererii (JSON)
{
"client": {
"name": "Maria Popescu",
"phone": "+37360000000",
"email": "maria@exemplu.md",
"dedupe": "both"
},
"pipeline": "Vânzări consultații",
"stage": "Lead nou",
"title": "Consultație somn 4 luni",
"source": "Formular website",
"warmth": "warm",
"lead_date": "2026-09-03",
"notes": "Vrea program de somn",
"child": { "name": "Ana", "age": 14, "age_unit": "weeks" },
"extra": { "utm_source": "facebook", "formular": "landing-somn" }
}Exemplu de cerere (cURL)
curl -X POST "$BASE/leads" \
-H "X-API-Key: CHEIA_TA" \
-H "Content-Type: application/json" \
-d '{
"client": { "name": "Maria Popescu", "phone": "+37360000000" },
"pipeline": "Vânzări consultații",
"stage": "Lead nou",
"source": "Formular website",
"warmth": "warm",
"child": { "age": 14, "age_unit": "weeks" }
}'Exemplu de răspuns
{
"ok": true,
"data": {
"client_exists": false,
"lead": {
"id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"client_id": "11111111-2222-4333-8444-555555555555",
"title": "Consultație somn 4 luni",
"pipeline": { "id": "3f1b9c2e-8a41-4d76-9f0a-2b7c5e6d1a33", "name": "Vânzări consultații" },
"stage": { "id": "8c2d0f11-55a7-4f2b-9c31-6d0be1f9a742", "name": "Lead nou" },
"source": "Formular website",
"warmth": "warm",
"consultant_id": null,
"lead_date": "2026-09-03",
"status": "open",
"notes": "Vrea program de somn\n\nutm_source: facebook\nformular: landing-somn",
"closed_at": null,
"created_at": "2026-09-03T09:30:00.000Z",
"updated_at": "2026-09-03T09:30:00.000Z"
},
"client": { "id": "11111111-2222-4333-8444-555555555555", "name": "Maria Popescu",
"children": [ { "id": "66666666-7777-4888-8999-aaaaaaaaaaaa", "name": "Ana",
"age": 14, "age_unit": "weeks", "age_declared_on": "2026-09-03", "notes": null } ],
"leads": [ { "id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff", "...": "..." } ],
"...": "..." },
"child_id": "66666666-7777-4888-8999-aaaaaaaaaaaa"
}
}Câmpurile răspunsului
| client_exists | boolean | `true` dacă clientul exista deja (dedupe sau `client_id`). |
| lead | object | Lead-ul creat (câmpurile de mai jos). |
| lead.id | uuid | Id-ul lead-ului. |
| lead.client_id | uuid | Clientul (persoana) căruia aparține lead-ul. |
| lead.title | string | null | Denumirea scurtă a lead-ului. |
| lead.pipeline | object | null | `{ id: uuid, name: string }`. |
| lead.stage | object | null | `{ id: uuid, name: string }` — etapa curentă. |
| lead.source | string | null | Numele sursei, exact cum e în lista de surse. |
| lead.warmth | enum("cold"|"warm"|"hot") | null | Gradul de interes. |
| lead.consultant_id | uuid | null | Consultantul atribuit. |
| lead.lead_date | date | Data lead-ului. |
| lead.status | enum("open"|"won"|"lost") | Starea lead-ului. |
| lead.notes | string | null | Notițele lead-ului. |
| lead.closed_at | datetime | null | Momentul închiderii (won/lost). |
| lead.created_at | datetime | Momentul creării. |
| lead.updated_at | datetime | null | Ultima modificare. |
| client | object | Clientul complet, cu copii și lead-uri. |
| child_id | uuid | null | Id-ul copilului creat din `child`, dacă a fost trimis. |
Erori posibile
{ "ok": false, "error": "Date invalide.", "code": "invalid_data",
"details": ["client_id: Trimite fie client_id, fie obiectul client."] }{ "ok": false, "error": "Etapa „Apel 5” nu există sau nu e activă în acest pipeline.",
"code": "invalid_data", "details": ["Lead nou", "Apel 1", "Vândut"] }{ "ok": false, "error": "Client not_found.", "code": "not_found" }{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/leads/{id}Detaliile unui lead
Lead-ul, clientul cu toate canalele de contact, istoricul de etape (`stage_history`), interacțiunile și vânzările atașate lead-ului.
Exemplu de cerere (cURL)
curl -X GET "$BASE/leads/bbbbbbbb-cccc-4ddd-8eee-ffffffffffff" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": {
"lead": { "id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff", "status": "open",
"pipeline": { "id": "3f1b9c2e-8a41-4d76-9f0a-2b7c5e6d1a33", "name": "Vânzări consultații" },
"stage": { "id": "b41e7a90-2c58-4f0d-8a17-9e3d5c6b2f08", "name": "Apel 1" }, "...": "..." },
"client": { "id": "11111111-2222-4333-8444-555555555555", "name": "Maria Popescu",
"phone": "+37360000000", "email": "maria@exemplu.md",
"telegram": null, "instagram": null, "messenger": null, "tiktok": null },
"stage_history": [
{ "id": "44444444-5555-4666-8777-888888888888", "entered_at": "2026-09-03T09:30:00.000Z",
"stage": { "id": "8c2d0f11-55a7-4f2b-9c31-6d0be1f9a742", "name": "Lead nou" } },
{ "id": "55555555-6666-4777-8888-999999999999", "entered_at": "2026-09-03T10:10:00.000Z",
"stage": { "id": "b41e7a90-2c58-4f0d-8a17-9e3d5c6b2f08", "name": "Apel 1" } }
],
"interactions": [ { "id": "22222222-3333-4444-8555-666666666666", "label": "Apel de calificare",
"date": "2026-09-03T10:15:00.000Z", "duration_minutes": 25, "fields": {}, "...": "..." } ],
"sales": [ { "id": "33333333-4444-4555-8666-777777777777", "amount": 890, "currency": "MDL",
"status": "paid", "...": "..." } ]
}
}Câmpurile răspunsului
| lead | object | Lead-ul (aceleași câmpuri ca la listare, fără `client`). |
| client | object | null | `{ id, name, phone, email, telegram, instagram, messenger, tiktok }`. |
| stage_history | array<object> | `{ id, entered_at, stage }`, în ordine cronologică. |
| interactions | array<object> | Interacțiunile lead-ului, cele mai noi primele. |
| sales | array<object> | Vânzările legate de lead. |
Erori posibile
{ "ok": false, "error": "ID invalid.", "code": "invalid_data" }{ "ok": false, "error": "Lead not_found.", "code": "not_found" }{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/leads/{id}Actualizează lead-ul
Se modifică doar câmpurile trimise. La `status: won|lost` se completează automat `closed_at` (la `open` se golește); schimbarea etapei adaugă un rând în istoric; schimbarea pipeline-ului fără `stage` mută lead-ul pe prima etapă a noului pipeline. Aceeași cale acceptă și `PUT` sau `POST`, cu comportament identic de update parțial.
Câmpurile cererii
| pipeline | string | Id sau nume de pipeline.(max 160) |
| stage | string | Id sau nume de etapă din pipeline.(max 160) |
| title | string | null | Denumirea lead-ului.(max 200) |
| source | string | null | Sursa; se creează dacă e nouă.(max 120) |
| warmth | enum("cold"|"warm"|"hot") | null | Gradul de interes. |
| consultant_id | uuid | null | Consultantul atribuit. |
| lead_date | date | Data lead-ului.(YYYY-MM-DD) |
| status | enum("open"|"won"|"lost") | Starea lead-ului. |
| notes | string | null | Notițele lead-ului.(max 4000) |
| notes_mode | enum("replace"|"append") | „append” adaugă la notițele existente, cu separator datat.(implicit „replace”) |
Exemplu de corp al cererii (JSON)
{
"stage": "Apel 1",
"warmth": "hot",
"consultant_id": "a1b2c3d4-e5f6-4708-9a1b-2c3d4e5f6071",
"status": "open",
"notes": "A cerut ofertă în scris",
"notes_mode": "append"
}Exemplu de cerere (cURL)
curl -X PATCH "$BASE/leads/bbbbbbbb-cccc-4ddd-8eee-ffffffffffff" \
-H "X-API-Key: CHEIA_TA" \
-H "Content-Type: application/json" \
-d '{ "stage": "Apel 1", "warmth": "hot" }'Exemplu de răspuns
{
"ok": true,
"data": {
"lead": {
"id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"client_id": "11111111-2222-4333-8444-555555555555",
"pipeline": { "id": "3f1b9c2e-8a41-4d76-9f0a-2b7c5e6d1a33", "name": "Vânzări consultații" },
"stage": { "id": "b41e7a90-2c58-4f0d-8a17-9e3d5c6b2f08", "name": "Apel 1" },
"warmth": "hot",
"status": "open",
"closed_at": null,
"notes": "Vrea program de somn\n\n— 03.09.2026, 13:05 —\nA cerut ofertă în scris",
"updated_at": "2026-09-03T10:05:00.000Z"
}
}
}Câmpurile răspunsului
| lead | object | Lead-ul după actualizare. |
| lead.id | uuid | Id-ul lead-ului. |
| lead.client_id | uuid | Clientul (persoana) căruia aparține lead-ul. |
| lead.title | string | null | Denumirea scurtă a lead-ului. |
| lead.pipeline | object | null | `{ id: uuid, name: string }`. |
| lead.stage | object | null | `{ id: uuid, name: string }` — etapa curentă. |
| lead.source | string | null | Numele sursei, exact cum e în lista de surse. |
| lead.warmth | enum("cold"|"warm"|"hot") | null | Gradul de interes. |
| lead.consultant_id | uuid | null | Consultantul atribuit. |
| lead.lead_date | date | Data lead-ului. |
| lead.status | enum("open"|"won"|"lost") | Starea lead-ului. |
| lead.notes | string | null | Notițele lead-ului. |
| lead.closed_at | datetime | null | Momentul închiderii (won/lost). |
| lead.created_at | datetime | Momentul creării. |
| lead.updated_at | datetime | null | Ultima modificare. |
Erori posibile
{ "ok": false, "error": "ID invalid.", "code": "invalid_data" }{ "ok": false, "error": "Lead not_found.", "code": "not_found" }{
"ok": false,
"error": "Date invalide.",
"code": "invalid_data",
"details": ["name: Required", "phone: String must contain at most 60 character(s)"]
}{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/leads/{id}/stageMută lead-ul într-o etapă
Scurtătură pentru automatizări și chatboți: un singur câmp. Etapa trebuie să aparțină pipeline-ului curent al lead-ului; mutarea se scrie în istoric.
Câmpurile cererii
| stage* | string | Id sau nume de etapă din pipeline-ul lead-ului.(1–160 caractere) |
Exemplu de corp al cererii (JSON)
{ "stage": "Apel 1" }Exemplu de cerere (cURL)
curl -X POST "$BASE/leads/bbbbbbbb-cccc-4ddd-8eee-ffffffffffff/stage" \
-H "X-API-Key: CHEIA_TA" \
-H "Content-Type: application/json" \
-d '{ "stage": "Apel 1" }'Exemplu de răspuns
{
"ok": true,
"data": {
"lead": {
"id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"stage": { "id": "b41e7a90-2c58-4f0d-8a17-9e3d5c6b2f08", "name": "Apel 1" },
"status": "open",
"updated_at": "2026-09-03T10:10:00.000Z"
}
}
}Câmpurile răspunsului
| lead | object | Lead-ul cu etapa nouă. |
Erori posibile
{ "ok": false, "error": "ID invalid.", "code": "invalid_data" }{ "ok": false, "error": "Lead not_found.", "code": "not_found" }{ "ok": false, "error": "Etapa „Apel 9” nu există sau nu e activă în acest pipeline.",
"code": "invalid_data", "details": ["Lead nou", "Apel 1", "Vândut"] }{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/leads/{id}Șterge lead-ul
Șterge definitiv lead-ul și datele atașate lui (istoric, interacțiuni, vânzări). Clientul rămâne.
Exemplu de cerere (cURL)
curl -X DELETE "$BASE/leads/bbbbbbbb-cccc-4ddd-8eee-ffffffffffff" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{ "ok": true, "data": { "deleted": true } }Câmpurile răspunsului
| deleted | boolean | `true` dacă ștergerea a reușit. |
Erori posibile
{ "ok": false, "error": "ID invalid.", "code": "invalid_data" }{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }Jurnalul de apeluri și întâlniri. Câmpurile personalizate ale tipului de interacțiune se trimit în `fields`, cu id-ul câmpului sau cu eticheta lui exactă drept cheie.
/api/public/v1/interactionsListează interacțiuni
Filtre pe `lead_id`, `client_id` și interval de timp, cele mai noi primele.
Parametri query
| lead_id | uuid | Interacțiunile unui lead. |
| client_id | uuid | Interacțiunile unui client. |
| from | datetime | `occurred_at` ≥ valoare.(date sau ISO 8601) |
| to | datetime | `occurred_at` ≤ valoare.(date sau ISO 8601) |
| limit | integer | Elemente pe pagină.(1–200, implicit 50) |
| page | integer | Pagina cerută.(≥ 1, implicit 1) |
Exemplu de cerere (cURL)
curl -X GET "$BASE/interactions?lead_id=bbbbbbbb-cccc-4ddd-8eee-ffffffffffff&from=2026-09-01" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{
"id": "22222222-3333-4444-8555-666666666666",
"client_id": "11111111-2222-4333-8444-555555555555",
"lead_id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"type": { "id": "d4e5f607-1829-4a31-c4d5-e6f708192a34", "name": "Apel de calificare" },
"label": "Apel de calificare",
"stage": { "id": "b41e7a90-2c58-4f0d-8a17-9e3d5c6b2f08", "name": "Apel 1" },
"date": "2026-09-03T10:15:00.000Z",
"duration_minutes": 25,
"outcome": "Programat pentru consultație",
"notes": null,
"fields": {
"e5f60718-2a3b-4b42-d5e6-f708192a3b45": "Somn de noapte",
"f6071829-3b4c-4c53-e6f7-08192a3b4c56": 4
},
"created_at": "2026-09-03T10:16:00.000Z"
}
],
"total": 3,
"page": 1,
"limit": 50
}Câmpurile răspunsului
| ok | boolean | `true` la succes. |
| data | array<object> | Elementele paginii curente. |
| total | integer | Numărul total de rânduri care corespund filtrelor. |
| page | integer | Pagina returnată (de la 1). |
| limit | integer | Numărul de elemente pe pagină. |
| data[].id | uuid | Id-ul interacțiunii. |
| data[].client_id | uuid | Clientul. |
| data[].lead_id | uuid | null | Lead-ul asociat. |
| data[].type | object | null | `{ id, name }` — tipul de interacțiune. |
| data[].label | string | Eticheta liberă (implicit numele tipului sau „apel”). |
| data[].stage | object | null | `{ id, name }` — etapa lead-ului la acel moment. |
| data[].date | datetime | Când a avut loc. |
| data[].duration_minutes | integer | null | Durata în minute. |
| data[].outcome | string | null | Rezultatul discuției. |
| data[].notes | string | null | Notițe. |
| data[].fields | object | Valorile câmpurilor personalizate, cu id-ul câmpului drept cheie. `{}` dacă nu există. |
| data[].created_at | datetime | Momentul înregistrării. |
Erori posibile
{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/interactionsÎnregistrează o interacțiune
Trimite `lead_id` sau `client_id` (atunci se folosește cel mai recent lead al clientului). Etapa se preia automat din lead. Valorile din `fields` se convertesc după formatul câmpului (`number` → număr, `checkbox` → boolean, restul → text), iar câmpurile obligatorii lipsă întorc 400 cu lista lor în `details`.
Câmpurile cererii
| lead_id* | uuid | Lead-ul. Alternativ trimite `client_id`. |
| client_id* | uuid | Clientul, dacă nu ai `lead_id`. |
| type | string | Id sau nume de tip de interacțiune.(max 160) |
| label | string | Etichetă liberă când nu trimiți `type`.(max 120, implicit numele tipului sau „apel”) |
| date | datetime | Când a avut loc.(ISO 8601, implicit acum) |
| duration_minutes | integer | Durata discuției.(0–1440) |
| outcome | string | Rezultatul discuției.(max 500) |
| notes | string | Notițe detaliate.(max 8000) |
| fields | object | Valorile câmpurilor personalizate; cheia poate fi id-ul câmpului sau eticheta exactă (fără diferență de majuscule). |
Exemplu de corp al cererii (JSON)
{
"lead_id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"type": "Apel de calificare",
"date": "2026-09-03T10:15:00.000Z",
"duration_minutes": 25,
"outcome": "Programat pentru consultație",
"notes": "Copilul se trezește de 4 ori pe noapte",
"fields": {
"Interes principal": "Somn de noapte",
"Nr. treziri pe noapte": 4,
"Rutina actuală": "Adoarme în brațe"
}
}Exemplu de cerere (cURL)
curl -X POST "$BASE/interactions" \
-H "X-API-Key: CHEIA_TA" \
-H "Content-Type: application/json" \
-d '{
"lead_id": "LEAD_ID",
"type": "Apel de calificare",
"duration_minutes": 25,
"outcome": "Programat pentru consultație",
"fields": { "Interes principal": "Somn de noapte" }
}'Exemplu de răspuns
{
"ok": true,
"data": {
"id": "22222222-3333-4444-8555-666666666666",
"client_id": "11111111-2222-4333-8444-555555555555",
"lead_id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"type": { "id": "d4e5f607-1829-4a31-c4d5-e6f708192a34", "name": "Apel de calificare" },
"label": "Apel de calificare",
"stage": { "id": "b41e7a90-2c58-4f0d-8a17-9e3d5c6b2f08", "name": "Apel 1" },
"date": "2026-09-03T10:15:00.000Z",
"duration_minutes": 25,
"outcome": "Programat pentru consultație",
"notes": "Copilul se trezește de 4 ori pe noapte",
"fields": {
"e5f60718-2a3b-4b42-d5e6-f708192a3b45": "Somn de noapte",
"f6071829-3b4c-4c53-e6f7-08192a3b4c56": 4,
"07182930-4c5d-4d64-f708-192a3b4c5d67": "Adoarme în brațe"
},
"created_at": "2026-09-03T10:16:00.000Z"
}
}Câmpurile răspunsului
| id | uuid | Id-ul interacțiunii. |
| client_id | uuid | Clientul. |
| lead_id | uuid | null | Lead-ul asociat. |
| type | object | null | `{ id, name }` — tipul de interacțiune. |
| label | string | Eticheta liberă (implicit numele tipului sau „apel”). |
| stage | object | null | `{ id, name }` — etapa lead-ului la acel moment. |
| date | datetime | Când a avut loc. |
| duration_minutes | integer | null | Durata în minute. |
| outcome | string | null | Rezultatul discuției. |
| notes | string | null | Notițe. |
| fields | object | Valorile câmpurilor personalizate, cu id-ul câmpului drept cheie. `{}` dacă nu există. |
| created_at | datetime | Momentul înregistrării. |
Erori posibile
{ "ok": false, "error": "Câmpuri obligatorii lipsă.", "code": "invalid_data",
"details": ["Interes principal"] }{ "ok": false, "error": "Tipul de interacțiune „Apel X” nu există.",
"code": "invalid_data", "details": ["Apel de calificare", "Consultație"] }{ "ok": false, "error": "Clientul nu are niciun lead.", "code": "not_found" }{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }Produsele atribuite clienților. Prețul și denumirea se salvează ca instantaneu, deci rămân corecte chiar dacă produsul se modifică sau se arhivează.
/api/public/v1/salesListează vânzări
Filtre pe `lead_id`, `client_id`, `status` și interval de date, cele mai recente primele.
Parametri query
| lead_id | uuid | Vânzările unui lead. |
| client_id | uuid | Vânzările unui client. |
| status | enum("paid"|"pending"|"refunded"|"free") | Starea plății. |
| from | date | Data vânzării ≥ valoare.(YYYY-MM-DD) |
| to | date | Data vânzării ≤ valoare.(YYYY-MM-DD) |
| limit | integer | Elemente pe pagină.(1–200, implicit 50) |
| page | integer | Pagina cerută.(≥ 1, implicit 1) |
Exemplu de cerere (cURL)
curl -X GET "$BASE/sales?client_id=11111111-2222-4333-8444-555555555555&status=paid" \
-H "X-API-Key: CHEIA_TA"Exemplu de răspuns
{
"ok": true,
"data": [
{
"id": "33333333-4444-4555-8666-777777777777",
"client_id": "11111111-2222-4333-8444-555555555555",
"lead_id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"product": { "id": "c3d4e5f6-0718-4920-b3c4-d5e6f7081923", "name": "Curs Montessori 0-6 luni" },
"produs_nume": "Curs Montessori 0-6 luni",
"quantity": 1,
"unit": "buc",
"amount": 890,
"currency": "MDL",
"status": "paid",
"date": "2026-09-03",
"consultant_id": null,
"notes": null,
"created_at": "2026-09-03T11:00:00.000Z"
}
],
"total": 1,
"page": 1,
"limit": 50
}Câmpurile răspunsului
| ok | boolean | `true` la succes. |
| data | array<object> | Elementele paginii curente. |
| total | integer | Numărul total de rânduri care corespund filtrelor. |
| page | integer | Pagina returnată (de la 1). |
| limit | integer | Numărul de elemente pe pagină. |
| data[].id | uuid | Id-ul vânzării. |
| data[].client_id | uuid | Clientul. |
| data[].lead_id | uuid | null | Lead-ul asociat. |
| data[].product | object | null | `{ id, name }` — produsul din catalog. |
| data[].produs_nume | string | null | Denumirea salvată ca instantaneu la vânzare. |
| data[].quantity | number | Cantitatea. |
| data[].unit | string | Unitatea de măsură (implicit „buc”). |
| data[].amount | number | Valoarea totală. |
| data[].currency | string | Moneda (ex. „MDL”). |
| data[].status | enum("paid"|"pending"|"refunded"|"free") | Starea plății. |
| data[].date | date | Data vânzării. |
| data[].consultant_id | uuid | null | Consultantul. |
| data[].notes | string | null | Notițe. |
| data[].created_at | datetime | Momentul înregistrării. |
Erori posibile
{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }/api/public/v1/salesÎnregistrează o vânzare
`product` acceptă id sau nume. Dacă nu trimiți `amount`, se calculează ca preț din catalog × `quantity`; moneda implicită e cea a produsului. Cu `client_id` se atașează automat cel mai recent lead al clientului, dacă există.
Câmpurile cererii
| lead_id* | uuid | Lead-ul. Alternativ trimite `client_id`. |
| client_id* | uuid | Clientul, dacă nu ai `lead_id`. |
| product* | string | Id sau nume de produs nearhivat.(1–200) |
| quantity | number | Cantitatea vândută.(0–100000, implicit 1) |
| unit | string | Unitatea de măsură (ex. „buc”, „zile”).(max 40, implicit „buc”) |
| amount | number | Valoarea totală.(0–10.000.000; implicit preț × cantitate) |
| currency | string | Moneda.(max 10, implicit moneda produsului) |
| date | date | Data vânzării.(YYYY-MM-DD, implicit azi) |
| status | enum("paid"|"pending"|"refunded"|"free") | Starea plății.(implicit „paid”) |
| consultant_id | uuid | null | Consultantul care a vândut. |
| notes | string | Notițe.(max 4000) |
Exemplu de corp al cererii (JSON)
{
"lead_id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"product": "Curs Montessori 0-6 luni",
"quantity": 1,
"unit": "buc",
"amount": 890,
"currency": "MDL",
"date": "2026-09-03",
"status": "paid",
"notes": "Plătit prin transfer"
}Exemplu de cerere (cURL)
curl -X POST "$BASE/sales" \
-H "X-API-Key: CHEIA_TA" \
-H "Content-Type: application/json" \
-d '{ "lead_id": "LEAD_ID", "product": "Curs Montessori 0-6 luni", "quantity": 1, "status": "paid" }'Exemplu de răspuns
{
"ok": true,
"data": {
"id": "33333333-4444-4555-8666-777777777777",
"client_id": "11111111-2222-4333-8444-555555555555",
"lead_id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
"product": { "id": "c3d4e5f6-0718-4920-b3c4-d5e6f7081923", "name": "Curs Montessori 0-6 luni" },
"produs_nume": "Curs Montessori 0-6 luni",
"quantity": 1,
"unit": "buc",
"amount": 890,
"currency": "MDL",
"status": "paid",
"date": "2026-09-03",
"consultant_id": null,
"notes": "Plătit prin transfer",
"created_at": "2026-09-03T11:00:00.000Z"
}
}Câmpurile răspunsului
| id | uuid | Id-ul vânzării. |
| client_id | uuid | Clientul. |
| lead_id | uuid | null | Lead-ul asociat. |
| product | object | null | `{ id, name }` — produsul din catalog. |
| produs_nume | string | null | Denumirea salvată ca instantaneu la vânzare. |
| quantity | number | Cantitatea. |
| unit | string | Unitatea de măsură (implicit „buc”). |
| amount | number | Valoarea totală. |
| currency | string | Moneda (ex. „MDL”). |
| status | enum("paid"|"pending"|"refunded"|"free") | Starea plății. |
| date | date | Data vânzării. |
| consultant_id | uuid | null | Consultantul. |
| notes | string | null | Notițe. |
| created_at | datetime | Momentul înregistrării. |
Erori posibile
{ "ok": false, "error": "Produsul „Curs X” nu există.", "code": "invalid_data",
"details": ["Curs Montessori 0-6 luni", "Consultație individuală"] }{ "ok": false, "error": "Lead not_found.", "code": "not_found" }{
"ok": false,
"error": "Date invalide.",
"code": "invalid_data",
"details": ["name: Required", "phone: String must contain at most 60 character(s)"]
}{ "ok": false, "error": "Cheie API invalidă sau dezactivată.", "code": "invalid_key" }{ "ok": false, "error": "Prea multe cereri. Încearcă mai târziu.", "code": "rate_limited" }| 400 | invalid_data | Câmpuri lipsă sau invalide. `details` listează problemele. |
| 401 | invalid_key | Header `X-API-Key` lipsă, greșit sau cheie dezactivată. |
| 404 | not_found | Clientul, lead-ul sau resursa cerută nu există. |
| 409 | conflict | Resursa există deja (duplicat detectat). |
| 429 | rate_limited | Peste 60 de cereri pe minut pentru aceeași cheie. |
| 500 | internal_error | Eroare neașteptată pe server. |