Integrează Recoma în site-ul tău
Un cod de reducere pe care îl poate da oricine îți aduce clienți — un influencer, un partener, un client mulțumit. Tu îl validezi la checkout și ne spui când s-a plasat comanda. Noi ținem socoteala: cine a adus vânzarea și cât are de încasat.
Toată integrarea are trei apeluri. Restul acestei pagini sunt detalii.
Pornire rapidă
Creezi o cheie în aplicație, la Setări → API. Cheia se vede o singură dată, la creare — noi păstrăm doar un hash, deci nu ți-o putem arăta a doua oară (și nici altcineva care ar ajunge la baza noastră de date).
Prima verificare — confirmă că merge cheia și îți spune în ce monedă lucrăm:
curl https://api.recoma.ro/v1/me \
-H "Authorization: Bearer rk_live_..."{
"seller": {
"id": "…",
"business_name": "Mobilier Fagul",
"currency": "RON",
"timezone": "Europe/Bucharest"
},
"key": { "prefix": "rk_live_7f3aQ2xd", "scopes": ["read", "redeem", "write"] }
}Fluxul complet, în trei pași:
| Când | Ce apelezi | Ce obții |
|---|---|---|
| Clientul scrie codul în coș | POST /v1/codes/{cod}/validate | reducerea de aplicat, sau motivul pentru care nu se aplică |
| Comanda a fost plasată | POST /v1/codes/{cod}/redeem | comisionul calculat și înregistrat |
| Comanda a fost returnată | POST /v1/redemptions/{id}/void | comisionul se întoarce, folosirea se eliberează |
Chei și scope-uri
Autentificarea este un header Authorization: Bearer rk_live_…. Fiecare cheie are unul sau mai multe scope-uri; dă-i fiecărei integrări strictul necesar.
| Scope | Ce permite |
|---|---|
read | listarea și citirea codurilor și a folosirilor |
redeem | înregistrarea unei comenzi și anularea ei |
write | crearea și modificarea codurilor |
O cheie revocată și una care nu a existat niciodată primesc exact același răspuns. E intenționat: altfel API-ul ar confirma care dintre încercările cuiva au fost cândva reale.
Autentificările eșuate se numără separat, per adresă IP — douăzeci pe minut. Traficul reușit nu se pune niciodată în contul adresei, deci mai multe magazine din spatele aceleiași conexiuni nu își împart o limită.
Limită: 120 de cereri pe minut per cheie. Peste ea primești 429 și un header Retry-After.
Validare cod
Nu consumă nimic. Poți să o apelezi oricât — inclusiv la fiecare tastă, în limita ratei.
curl https://api.recoma.ro/v1/codes/MARIA10/validate \
-H "Authorization: Bearer rk_live_..." \
-H "Content-Type: application/json" \
-d '{ "order_value": 1000 }'{
"code": "MARIA10",
"valid": true,
"reason": null,
"state": "active",
"display_text": "10% la orice comandă",
"discount": { "kind": "percent", "value": 10, "min_order_value": 200,
"max_discount_amount": 150 },
"currency": "RON",
"remaining": 498,
"referrer": { "name": "Maria Popescu" },
"applies_to": { "order_value": 1000, "discount_amount": 100,
"net_amount": 900, "free_shipping": false }
}valid și reason.Motive posibile: not_found, paused, archived, scheduled, expired, exhausted, below_minimum, customer_limit_reached.
order_value este valoarea produselor înainte de reducere, fără transport. Codul se caută iertător: mări a10, maria10 și MARIA10 duc toate la același cod.
Pentru free_shipping, discount_amount este 0 — nu știm cât încasezi tu pe livrare, iar o presupunere ar ajunge într-un calcul de comision. Acționează pe free_shipping.
Înregistrare comandă
Se apelează după ce comanda e plasată. Consumă o folosire, calculează comisionul și e ceea ce ajunge în extrasul lunar al celui care a recomandat.
curl https://api.recoma.ro/v1/codes/MARIA10/redeem \
-H "Authorization: Bearer rk_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042" \
-d '{ "order_value": 1000, "order_ref": "#1042" }'{
"id": "9c1f…",
"code": "MARIA10",
"order_ref": "#1042",
"status": "confirmed",
"order_value": 1000,
"discount_amount": 100,
"net_amount": 900,
"currency": "RON",
"commission_percent": 4,
"commission_amount": 36,
"redeemed_at": "2026-07-29T09:14:22Z"
}Comisionul se calculează pe net_amount — cât ai încasat efectiv pe produse, după reducere. Nu pe prețul de listă: altfel ai plăti comision din bani care nu au intrat niciodată.
Dacă un cod nu se poate aplica, primești 409 cu motivul exact: code_exhausted, code_expired, code_paused, below_minimum, customer_limit_reached.
customer_ref este necesar doar pentru codurile care limitează folosirile per client. Trimite ce ai tu — un email, un id intern. Noi stocăm doar un digest cu sare, nu valoarea: limita funcționează fără ca noi să ajungem să deținem lista ta de clienți.
Anulare / retur
Comanda a fost returnată sau anulată. Comisionul se inversează, folosirea se dă înapoi codului, iar order_ref redevine disponibil — dacă acel client comandă din nou, este o vânzare nouă și o poți înregistra.
curl https://api.recoma.ro/v1/redemptions/9c1f.../void \
-H "Authorization: Bearer rk_live_..." \
-H "Content-Type: application/json" \
-d '{ "reason": "retur" }'Se refuză după ce luna de decontare s-a închis (month_locked). Redeschiderea se face în doi, din aplicație — nu de aici.
Administrare coduri
Poți crea și modifica coduri și din API, nu doar din aplicație — util dacă vrei un cod pentru fiecare influencer, generat din propriul tău panou.
{
"code": "MARIA10",
"label": "Maria — Instagram",
"display_text": "10% la orice comandă",
"discount": {
"kind": "percent",
"value": 10,
"min_order_value": 200,
"max_discount_amount": 150
},
"commission_percent": 4,
"max_per_customer": 1,
"payee": {
"name": "Maria Popescu",
"handle": "@maria.deco",
"email": "maria@example.com"
}
}payee este cine câștigă din cod. Nu are nevoie de cont: îi scrii numele și codul funcționează. Mai târziu o poți invita, iar când acceptă, tot ce a adus codul până atunci trece în contul ei — istoricul o urmează.
Codul este unic în contul tău, nu global: dacă altă firmă folosește deja numele la care te gândeai, el rămâne disponibil pentru tine.
Un cod nu poate fi redenumit. E tipărit, postat și spus cu voce tare; dacă s-ar putea schimba, s-ar rupe în tăcere peste tot unde există deja. Arhivează-l și creează altul.
Codurile au și o stare derivată. status e ce a ales un om (active, paused, archived); state e ce este adevărat acum și include scheduled, expired, exhausted. Ia deciziile după state.
Erori
Orice eșec are aceeași formă:
{
"error": {
"type": "conflict",
"code": "code_exhausted",
"message": "This code has reached its maximum number of uses."
}
}Ramifică pe code — este stabil și nu se va reformula niciodată. type este categoria generală, pentru tratare generică. message este în engleză, scris pentru tine, și se poate schimba oricând: nu-l arăta niciodată clientului. Textul pentru cumpărător îl scrii tu, în limba lui.
| HTTP | type | Când |
|---|---|---|
400 | invalid_request | lipsește sau e greșit un câmp; `param` spune care |
401 | authentication_error | cheie lipsă, greșită sau revocată |
403 | permission_error | cheia nu are scope-ul necesar |
404 | not_found | obiectul nu există în acest cont |
409 | conflict | există, dar starea lui refuză operațiunea |
429 | rate_limit | prea multe cereri |
503 | service_unavailable | nu s-a decis nimic — reîncearcă |
500 | server_error | problema e la noi |
Lista completă a codurilor, cu ce înseamnă fiecare, e în docs/openapi.yaml.
Reîncercări
503 temporarily_unavailable înseamnă că cererea nu a ajuns la o concluzie — o contenție, un timeout, o clipă în care baza de date nu a răspuns. Nu e un refuz și nu e o problemă a cererii tale. Reîncearc-o, cu același Idempotency-Key.
redeem e ambiguu — s-a înregistrat comanda sau nu? Cu cheia de idempotență poți afla în siguranță: dacă apucase să se înregistreze, primești înapoi exact aceeași înregistrare, cu "replayed": true. Fără ea, singura variantă e să ghicești.500 internal_error e la noi. Reîncercarea e la fel de sigură, dar rareori ajută imediat.
Tot ce e în zona 4xx înseamnă că trebuie schimbată cererea. Reîncercată neschimbată, va eșua identic.
Idempotență
Trimite un header Idempotency-Key la fiecare redeem. Orice șir stabil între 8 și 200 de caractere — numărul comenzii e o alegere bună.
O cerere reluată cu aceeași cheie returnează înregistrarea originală, cu "replayed": true, în loc să calculeze un al doilea comision. Corpul reluării este ignorat. Statusul este 200, nu 201 — tratează-l la fel.
Ca plasă de siguranță, același order_ref pe același cod este oricum refuzat. Ești acoperit în ambele feluri, dar header-ul e cel care îți permite să reîncerci fără să te gândești.
Următorul pas
Ghiduri concrete pentru WooCommerce și Shopify. Specificația completă OpenAPI 3.1 este în depozitul de cod, la docs/openapi.yaml.
Nu ai încă un cont? Creează unul gratuit — cheile se generează din Setări → API.

