Început rapid
- Primește cheile. Operatorul de transport cu care lucrezi îți creează un canal în consola lui: Canale de vânzare → Canal nou (tip „agenție” sau „API”), cu comisionul și, opțional, doar anumite trasee. Primești un
Requestor-Idși o cheie API, afișate o singură dată. Păstrează cheia doar pe serverul tău, niciodată în aplicația din telefon sau în JavaScript-ul din browser. - Fă primul apel:
curl https://biletebus.ro/api/partner/v1/ \
-H "X-Requestor-Id: BBXXXXXXXX" \
-H "X-Api-Key: cheia-ta-secreta"
{
"ok": true,
"canal": {
"nume": "Agenția Test",
"fel": "agentie",
"requestor_id": "BBS7RB78S2",
"comision_procent": 5,
"operator": {
"slug": "carpatica",
"nume": "Carpatica Trans"
},
"trasee_permise": null
}
}
Adresa de bază este https://biletebus.ro/api/partner/v1. Toate apelurile folosesc HTTPS.
Autentificare
Fiecare cerere trimite două antete: X-Requestor-Id (identificatorul canalului) și X-Api-Key (cheia secretă). Păstrăm doar amprenta criptografică a cheii, deci nici noi nu o putem vedea. Dacă o pierzi, operatorul îți creează alt canal și îl oprește pe cel vechi. Credențiale greșite sau un canal oprit întorc 401.
Un canal aparține unui singur operator și vede doar cursele acestuia (sau doar traseele permise). Rezervările făcute de un canal pot fi citite și anulate doar de același canal.
Convenții
- Cererile și răspunsurile sunt JSON (
Content-Type: application/json), în UTF-8. Numele câmpurilor sunt în română, fără diacritice. - Fiecare răspuns are
"ok": truesau, la eroare,"ok": falseși un"mesaj"în română, pe care îl poți arăta clientului. - Sumele sunt în lei (
RON), cu cel mult două zecimale. Prețurile includ TVA (tva_procentpe fiecare bilet). - Datele sunt
AAAA-LL-ZZ, iar orele sunt ora locală a României:"2026-10-24 04:00". - Localitățile se dau prin
slug(ex.constanta,bucuresti) sau prinid. Lista vine de laGET /localitatiși cuprinde toate cele 13.749 de localități din România (registrul SIRUTA al INS), sate incluse. - Categorii de pasageri:
adult,copil,elev,student,pensionar. Fiecare operator își stabilește reducerile.
Fluxul unei vânzări
GET /cautare: curse, ore, prețuri și locuri libere pentru o zi.GET /curse/:id(opțional): harta locurilor, ca să lași clientul să aleagă.POST /sesiuni: blochează locurile pentru 15 minute și fixează prețul.POST /sesiuni/:id/finalizare: datele pasagerilor. Biletele sunt emise, cu codurile QR.- Mai târziu:
GET /rezervari/:codpentru stare șiPOST /rezervari/:cod/anularepentru anulare.
Locurile sunt vândute pe segmente: un loc ocupat București → Pitești rămâne liber Pitești → Sibiu. Nu se poate vinde același loc de două ori, nici când mai multe canale vând în aceeași secundă.
Referință API
GET /
Canalul tău
Numele canalului, operatorul, comisionul și traseele permise (null = toate). Bun pentru a verifica cheile.
Răspuns
{
"ok": true,
"canal": {
"nume": "Agenția Test",
"fel": "agentie",
"requestor_id": "BBS7RB78S2",
"comision_procent": 5,
"operator": {
"slug": "carpatica",
"nume": "Carpatica Trans"
},
"trasee_permise": null
}
}GET /localitati
Localități
Caută localități după nume. Diacriticele sunt opționale („brasov” găsește „Brașov”). Satele au în comuna comuna de care aparțin.
| Parametru | Tip | Descriere |
|---|---|---|
q | text | Nume sau început de nume. Fără q și fără cu_curse primești toată lista. |
cu_curse | 1 | Doar localitățile din care sau spre care canalul tău are curse. |
Răspuns
{
"ok": true,
"localitati": [
{
"id": 4,
"nume": "Constanța",
"slug": "constanta",
"judet": "CT",
"tara": "RO",
"tip": "municipiu",
"comuna": "municipiul Constanța"
}
]
}GET /cautare
Caută curse
Cursele dintr-o zi între două localități, cu prețul pentru pasagerii ceruți (total), locurile libere și ofertele aplicate. vanzare_online: true înseamnă că se poate rezerva acum.
| Parametru | Tip | Descriere |
|---|---|---|
de obligatoriu | slug | id | Localitatea de plecare |
pana obligatoriu | slug | id | Destinația |
data | AAAA-LL-ZZ | Implicit: azi |
adult, copil, elev, student, pensionar | număr | Câți pasageri din fiecare categorie (implicit 1 adult, maximum 9). |
Răspuns
{
"ok": true,
"comision_procent": 5,
"curse": [
{
"cursa_id": 57,
"data": "2026-10-24",
"pleaca": "2026-10-24 04:00",
"ajunge": "2026-10-24 08:35",
"durata_min": 275,
"operator": {
"id": 1,
"slug": "carpatica",
"nume": "Carpatica Trans",
"scurt": "CT",
"culoare": "#1b46ee",
"telefon": "0700 000 101",
"rating": 4.7
},
"traseu": {
"id": 1,
"cod": "K1",
"nume": "Constanța – Otopeni",
"tip": "regulat",
"international": false
},
"confirmata": true,
"minim_pasageri": null,
"nota": null,
"de": {
"ordine": 0,
"statie_id": 6,
"statie": "Autogara Sud",
"statie_slug": "autogara-sud",
"tip": "autogara",
"localitate": "Constanța",
"localitate_slug": "constanta"
},
"pana": {
"ordine": 3,
"statie_id": 4,
"statie": "Aeroport Henri Coandă — Sosiri",
"statie_slug": "aeroport-henri-coanda-sosiri",
"tip": "aeroport",
"localitate": "Otopeni",
"localitate_slug": "otopeni"
},
"opriri": [
{
"ordine": 0,
"statie": "Autogara Sud",
"localitate": "Constanța",
"km": 0,
"ora": "04:00"
}
],
"directa": true,
"dotari": [
"wifi"
],
"bagaj": "1 bagaj de cală + 1 de mână",
"locuri_libere": 49,
"locuri_total": 49,
"pret_adult": 75,
"pret_adult_lista": 75,
"oferta": null,
"preturi": {
"adult": {
"pret": 75,
"pret_lista": 75,
"fel": "dus",
"oferta": null,
"flex": []
}
},
"total": 150,
"moneda": "RON",
"vanzare_online": true,
"plata_la_urcare": true,
"plata_card": true,
"stare": "programata",
"mesaj": null
}
]
}GET /curse/:id
Detaliile unei curse
Prețul pe segment, toate opririle cu ore și km, schema autocarului și locurile ocupate pe segmentul cerut.
| Parametru | Tip | Descriere |
|---|---|---|
de_statie | id | de.statie_id din căutare |
pana_statie | id | pana.statie_id din căutare |
adult, copil, … | număr | Ca la căutare |
Răspuns
{
"ok": true,
"cursa": {
"cursa_id": 57,
"data": "2026-10-24",
"pleaca": "2026-10-24 04:00",
"ajunge": "2026-10-24 08:35",
"durata_min": 275,
"operator": {
"id": 1,
"slug": "carpatica",
"nume": "Carpatica Trans",
"scurt": "CT",
"culoare": "#1b46ee",
"telefon": "0700 000 101",
"rating": 4.7
},
"traseu": {
"id": 1,
"cod": "K1",
"nume": "Constanța – Otopeni",
"tip": "regulat",
"international": false
},
"confirmata": true,
"minim_pasageri": null,
"nota": null,
"de": {
"ordine": 0,
"statie_id": 6,
"statie": "Autogara Sud",
"statie_slug": "autogara-sud",
"tip": "autogara",
"localitate": "Constanța",
"localitate_slug": "constanta"
},
"pana": {
"ordine": 3,
"statie_id": 4,
"statie": "Aeroport Henri Coandă — Sosiri",
"statie_slug": "aeroport-henri-coanda-sosiri",
"tip": "aeroport",
"localitate": "Otopeni",
"localitate_slug": "otopeni"
},
"opriri": [
{
"ordine": 0,
"statie": "Autogara Sud",
"localitate": "Constanța",
"km": 0,
"ora": "04:00"
},
{
"ordine": 1,
"statie": "Autogara Medgidia",
"localitate": "Medgidia",
"km": 36.3,
"ora": "04:45"
},
{
"ordine": 2,
"statie": "Autogara Slobozia",
"localitate": "Slobozia",
"km": 133.1,
"ora": "06:25"
}
],
"directa": true,
"dotari": [
"wifi",
"prize",
"ac"
],
"bagaj": "1 bagaj de cală + 1 de mână",
"locuri_libere": 49,
"locuri_total": 49,
"pret_adult": 75,
"pret_adult_lista": 75,
"oferta": null,
"preturi": {
"adult": {
"pret": 75,
"pret_lista": 75,
"fel": "dus",
"oferta": null,
"flex": []
}
},
"total": 150,
"moneda": "RON",
"vanzare_online": true,
"plata_la_urcare": true,
"plata_card": true,
"stare": "programata",
"mesaj": null
},
"circuit": [
{
"ordine": 0,
"statie_id": 6,
"statie": "Autogara Sud",
"localitate": "Constanța",
"km": 0,
"ora": "04:00",
"urcare": true,
"coborare": false
},
{
"ordine": 1,
"statie_id": 10,
"statie": "Autogara Medgidia",
"localitate": "Medgidia",
"km": 36.3,
"ora": "04:45",
"urcare": true,
"coborare": true
},
{
"ordine": 2,
"statie_id": 34,
"statie": "Autogara Slobozia",
"localitate": "Slobozia",
"km": 133.1,
"ora": "06:25",
"urcare": true,
"coborare": true
}
],
"locuri": 49,
"schema": {
"randuri": [
[
1,
2,
null
],
[
5,
6,
null
],
[
9,
10,
null
]
],
"sofer": "stanga",
"usi": [
1,
6
]
},
"ocupate": []
}POST /sesiuni
Blochează locuri (15 minute)
Pentru dus-întors trimite două elemente în curse. Fără locuri, alegem noi locuri alăturate. Răspunsul conține prețul final, valabil până la expira_la.
Corp (JSON)
{
"curse": [{ "cursa_id": 57, "de_statie_id": 6, "pana_statie_id": 4, "locuri": [1, 2] }],
"pasageri": [{ "categorie": "adult" }, { "categorie": "adult" }]
}
Răspuns
{
"ok": true,
"sesiune": "48a8a37ddfae1c2529a3c5e1",
"expira_la": "2026-10-23 02:29:26",
"total": 150,
"moneda": "RON",
"operator_id": 1,
"legs": [
{
"cursa_id": 57,
"traseu_id": 1,
"a": 0,
"b": 3,
"de_statie_id": 6,
"pana_statie_id": 4,
"pleaca": "2026-10-24 04:00:00",
"international": false,
"locuri": [
1,
2
],
"linii": [
{
"categorie": "adult",
"pret": 75,
"pret_lista": 75,
"oferta_id": null,
"tva": 11,
"tarif_id": 5,
"fel": "dus"
},
{
"categorie": "adult",
"pret": 75,
"pret_lista": 75,
"oferta_id": null,
"tva": 11,
"tarif_id": 5,
"fel": "dus"
}
]
}
]
}DELETE /sesiuni/:id
Eliberează locurile
Dacă clientul renunță, eliberează imediat locurile în loc să aștepți cele 15 minute.
POST /sesiuni/:id/finalizare
Emite biletele
Primește datele pasagerilor în aceeași ordine ca la /sesiuni. Clientul poate plăti în două feluri. metoda_plata: "card" (implicit) înseamnă că agenția a încasat banii și decontează cu operatorul. "la_urcare" înseamnă că pasagerul plătește șoferului. Pentru cursele internaționale, act și nastere sunt obligatorii. Pasagerul primește SMS cu biletul.
| Parametru | Tip | Descriere |
|---|---|---|
pasageri[].nume obligatoriu | text | Numele complet |
pasageri[].act | text | Seria și numărul actului |
pasageri[].nastere | AAAA-LL-ZZ | Data nașterii |
contact.telefon obligatoriu | text | Telefonul clientului (biletul vine prin SMS) |
contact.email | text | |
metoda_plata | "card" | "la_urcare" | |
voucher | text | Cod de reducere al operatorului |
factura | obiect | Datele de facturare ale clientului, păstrate pe rezervare |
observatii | text | Cel mult 500 de caractere |
Corp (JSON)
{
"pasageri": [{ "nume": "Ion Popescu", "act": "CT123456" }, { "nume": "Maria Popescu" }],
"contact": { "telefon": "0722111222", "email": "[email protected]" },
"metoda_plata": "card"
}
Răspuns
{
"ok": true,
"rezervare": {
"cod": "XFT2K5A4",
"operatie": "vanzare",
"stare": "activa",
"platita": true,
"metoda_plata": "card",
"asteapta_card": false,
"total": 150,
"reducere": 0,
"de_plata": 150,
"moneda": "RON",
"plata_pana": null,
"creat_la": "2026-10-23 02:14:26",
"operator": {
"nume": "Carpatica Trans",
"slug": "carpatica",
"telefon": "0700 000 101"
},
"canal": "agentie",
"contact": {
"telefon": "+40722111222",
"email": "[email protected]"
},
"factura": null,
"bilete": [
{
"cod": "PJ6ZUBM2",
"qr": "BB1:PJ6ZUBM2:hyOZbeOG-x2b",
"stare": "vandut",
"categorie": "adult",
"fel": "dus",
"pret": 75,
"tva_procent": 11,
"pasager": "Ion Popescu",
"loc": 1,
"cursa_id": 57,
"traseu": "Constanța – Otopeni",
"traseu_cod": "K1",
"pleaca": "2026-10-24 04:00",
"ajunge": "2026-10-24 08:35",
"de": {
"statie": "Autogara Sud",
"localitate": "Constanța"
},
"pana": {
"statie": "Aeroport Henri Coandă — Sosiri",
"localitate": "Otopeni"
}
},
{
"cod": "KJM8SC3D",
"qr": "BB1:KJM8SC3D:euMZ9sF0WR4Z",
"stare": "vandut",
"categorie": "adult",
"fel": "dus",
"pret": 75,
"tva_procent": 11,
"pasager": "Maria Popescu",
"loc": 2,
"cursa_id": 57,
"traseu": "Constanța – Otopeni",
"traseu_cod": "K1",
"pleaca": "2026-10-24 04:00",
"ajunge": "2026-10-24 08:35",
"de": {
"statie": "Autogara Sud",
"localitate": "Constanța"
},
"pana": {
"statie": "Aeroport Henri Coandă — Sosiri",
"localitate": "Otopeni"
}
}
],
"extra": [],
"rambursari": []
}
}Fiecare bilet are un cod și un qr semnat: tipărește sau afișează qr ca cod QR. Șoferul îl scanează la urcare.
GET /rezervari
Rezervările canalului
Cele mai noi întâi, cel mult 500, cu comisionul tău pe fiecare. Bun pentru decontul lunar.
| Parametru | Tip | Descriere |
|---|---|---|
de | AAAA-LL-ZZ | Data creării, implicit acum 30 de zile |
pana | AAAA-LL-ZZ | Implicit azi |
Răspuns
{
"ok": true,
"de": "2026-09-23",
"pana": "2026-10-23",
"rezervari": [
{
"cod": "XFT2K5A4",
"operatie": "vanzare",
"stare": "activa",
"platita": true,
"total": 150,
"reducere": 0,
"de_plata": 150,
"comision": 7.5,
"moneda": "RON",
"creat_la": "2026-10-23 02:14:26"
}
]
}GET /rezervari/:cod
O rezervare
Starea la zi: bilete, locuri, îmbarcări, rambursări.
Răspuns
{
"ok": true,
"rezervare": {
"cod": "XFT2K5A4",
"operatie": "vanzare",
"stare": "activa",
"platita": true,
"metoda_plata": "card",
"asteapta_card": false,
"total": 150,
"reducere": 0,
"de_plata": 150,
"moneda": "RON",
"plata_pana": null,
"creat_la": "2026-10-23 02:14:26",
"operator": {
"nume": "Carpatica Trans",
"slug": "carpatica",
"telefon": "0700 000 101"
},
"canal": "agentie",
"contact": {
"telefon": "+40722111222",
"email": "[email protected]"
},
"factura": null,
"bilete": [
{
"cod": "PJ6ZUBM2",
"qr": "BB1:PJ6ZUBM2:hyOZbeOG-x2b",
"stare": "vandut",
"categorie": "adult",
"fel": "dus",
"pret": 75,
"tva_procent": 11,
"pasager": "Ion Popescu",
"loc": 1,
"cursa_id": 57,
"traseu": "Constanța – Otopeni",
"traseu_cod": "K1",
"pleaca": "2026-10-24 04:00",
"ajunge": "2026-10-24 08:35",
"de": {
"statie": "Autogara Sud",
"localitate": "Constanța"
},
"pana": {
"statie": "Aeroport Henri Coandă — Sosiri",
"localitate": "Otopeni"
}
},
{
"cod": "KJM8SC3D",
"qr": "BB1:KJM8SC3D:euMZ9sF0WR4Z",
"stare": "vandut",
"categorie": "adult",
"fel": "dus",
"pret": 75,
"tva_procent": 11,
"pasager": "Maria Popescu",
"loc": 2,
"cursa_id": 57,
"traseu": "Constanța – Otopeni",
"traseu_cod": "K1",
"pleaca": "2026-10-24 04:00",
"ajunge": "2026-10-24 08:35",
"de": {
"statie": "Autogara Sud",
"localitate": "Constanța"
},
"pana": {
"statie": "Aeroport Henri Coandă — Sosiri",
"localitate": "Otopeni"
}
}
],
"extra": [],
"rambursari": []
}
}POST /rezervari/:cod/anulare
Anulează
Anulează toată rezervarea sau doar unele bilete ({"bilete": ["PJ6ZUBM2"]}). Suma rambursată urmează regulile de anulare ale operatorului (cât reține în funcție de cât timp mai e până la plecare). Biletele dus-întors se anulează împreună.
Răspuns
{
"ok": true,
"rezervare": "XFT2K5A4",
"rambursat_total": 150,
"linii": [
{
"bilet": "PJ6ZUBM2",
"platit": 75,
"retinut": 0,
"rambursat": 75,
"procent_retinut": 0
},
{
"bilet": "KJM8SC3D",
"platit": 75,
"retinut": 0,
"rambursat": 75,
"procent_retinut": 0
}
]
}Erori și limite
| Cod | Când |
|---|---|
400 | Date greșite sau incomplete. mesaj spune ce lipsește. |
401 | Credențiale greșite sau canal oprit. |
404 | Nu există sau nu aparține canalului tău. |
409 | Conflict: locul tocmai a fost luat, sesiunea a expirat, cursa a plecat. Reia de la căutare. |
429 | Prea multe cereri: cel mult 600 pe minut de pe aceeași adresă IP. |
5xx | Eroare la noi. Reîncearcă peste câteva secunde. |
{
"ok": false,
"mesaj": "Rezervarea nu există pe acest canal."
}
Atenție la reîncercări: dacă /finalizare nu răspunde (de exemplu la un timeout), nu o trimite din nou orbește. Verifică întâi în GET /rezervari dacă rezervarea s-a făcut. Sesiunea poate fi finalizată o singură dată.
Webhooks (pentru operatori)
Operatorii își adaugă o adresă în consolă: Integrări → Webhooks. La fiecare eveniment trimitem imediat un POST cu JSON la adresa respectivă. Exemple de destinații: programul de facturare, contabilitatea, un CRM sau un automatism (Make, Zapier, n8n).
| Eveniment | Când |
|---|---|
rezervare.creata | Rezervare nouă: vânzare, plată la urcare sau în așteptarea plății cu cardul. obiect = rezervarea completă. |
rezervare.platita | O rezervare neplătită a fost plătită (card confirmat sau încasată la urcare). |
rezervare.anulata | Bilete anulate sau rambursate: sumele pe fiecare bilet, plus rezervarea la zi. |
rezervare.expirata | O rezervare neplătită a expirat și locurile au fost eliberate. |
bilet.amanat | Bilet transformat în voucher pentru o călătorie ulterioară. |
bilet.imbarcat | Pasager scanat la urcare. |
cursa.anulata | Cursă anulată de operator, cu lista rezervărilor afectate. |
cursa.confirmata | Cursă ocazională confirmată (s-a atins minimul de pasageri). |
POST https://firma-ta.ro/webhook
Content-Type: application/json
Biletebus-Event: rezervare.creata
Biletebus-Delivery: 1842
Biletebus-Signature: t=1792716842,v1=5e0c…
{ "id": "evt_9b1e…", "tip": "rezervare.creata", "creat_la": "2026-10-23T09:14:02.511Z", "operator": "firma-ta", "obiect": { "cod": "XFT2K5A4", … } }
Verifică semnătura înainte să crezi mesajul: v1 = HMAC-SHA256(secret, t + "." + corpul exact primit). Respinge mesajele cu t mai vechi de 5 minute. Secretul (whsec_…) apare o singură dată, când adaugi adresa.
// Node.js
const crypto = require('crypto')
function verifica(corp, antet, secret) {
const [, t, v1] = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(antet || '') || []
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false
const asteptat = crypto.createHmac('sha256', secret).update(t + '.' + corp).digest('hex')
return crypto.timingSafeEqual(Buffer.from(v1, 'hex'), Buffer.from(asteptat, 'hex'))
}
<?php // PHP
$corp = file_get_contents('php://input');
preg_match('/^t=(\d+),v1=([0-9a-f]{64})$/', $_SERVER['HTTP_BILETEBUS_SIGNATURE'] ?? '', $m);
$ok = $m && abs(time() - (int)$m[1]) <= 300
&& hash_equals(hash_hmac('sha256', $m[1] . '.' . $corp, $SECRET), $m[2]);
if (!$ok) { http_response_code(400); exit; }
$ev = json_decode($corp, true); // $ev['tip'], $ev['obiect']
http_response_code(200);
Răspunde cu un cod 2xx în cel mult 10 secunde. Altfel reîncercăm după 1 min, 5 min, 30 min, 2 h, 6 h, 12 h și 24 h. Câmpul id rămâne același la reîncercări, ca să nu procesezi de două ori același eveniment. Acceptăm doar adrese https:// publice. Din consolă poți trimite un mesaj de test, vezi istoricul livrărilor și poți retrimite orice livrare.
Widget pentru site
Pune pe orice pagină (WordPress, Wix, HTML) o casetă de căutare doar cu cursele firmei tale. Rezervarea se deschide pe biletebus.ro, cu plata și biletul ca de obicei. Codul gata făcut, cu previzualizare, e în consolă la Integrări.
<script src="https://biletebus.ro/widget.js" data-operator="firma-ta" async></script>
| Atribut | Ce face |
|---|---|
data-operator | Obligatoriu: identificatorul firmei (din adresa paginii ei pe biletebus.ro). |
data-culoare | Culoarea butoanelor, ex. #c81e1e. Implicit, culoarea firmei. |
data-de, data-pana | Ruta preselectată, ex. constanta și otopeni. |
data-tema | light (implicit), dark sau auto (după setarea telefonului vizitatorului). |
data-latime | Lățimea maximă, implicit 760px. |
data-tinta | Selector CSS al elementului în care să apară, ex. #rezervari. Implicit, chiar sub cod. |
Înălțimea casetei se ajustează singură. Caseta nu pune cookie-uri pe site-ul tău și nu citește nimic de pe el.
Orar GTFS
GTFS este formatul standard pentru orare, folosit de Google Maps, Moovit, Transit și planificatoarele de călătorii. Fluxul se actualizează automat din orarele din consolă:
https://biletebus.ro/api/public/gtfs.zip # toți operatorii
https://biletebus.ro/api/public/gtfs.zip?operator=firma-ta # o singură firmă
Operatorii își pot și importa orarul dintr-un fișier GTFS sau Excel (Import / Export în consolă).
OpenAPI / Postman
Descrierea completă a API-ului de vânzare în format OpenAPI 3.1: openapi.json. Importă fișierul în Postman, Insomnia sau într-un generator de cod (ex. openapi-generator) ca să ai pe loc un client în limbajul tău.
Versiune API: v1. Schimbările care pot strica integrări existente vor apărea într-o versiune nouă (/v2), iar v1 va rămâne disponibilă cel puțin 12 luni. Întrebări: scrie-ne de pe pagina Ajutor.