Za razvijalce

    Javni API in webhooki

    Povežite ProEntry s svojo spletno stranjo, Zapierjem ali internim sistemom. Prek REST API-ja berete delovni čas, storitve, račune in rezervacije ter ustvarjate povpraševanja v CRM; z izhodnimi webhooki pa vas ProEntry sam obvesti o novih povpraševanjih, rezervacijah in plačilih.

    API dostop je na voljo v paketih Pro, Ekipa in Premium.

    Avtentikacija

    API ključ ustvarite v aplikaciji: Nastavitve → API dostop. Ključe lahko ustvarja in prekliče lastnik ali vodja podjetja; na podjetje je lahko aktivnih največ 10 ključev. Ključ ima obliko pe_live_ + 32 znakov in se v celoti prikaže samo enkrat, ob kreaciji — shranite ga varno, kasneje je viden le začetek ključa.

    Ključ pošljete z vsakim zahtevkom na enega od dveh načinov (Bearer ima prednost):

    Authorization: Bearer pe_live_...
    # ali
    X-Api-Key: pe_live_...

    Vsak ključ dobi ob kreaciji podmnožico scope-ov (npr. invoices:read) — endpoint brez ustreznega scope-a vrne 403 insufficient_scope. Preklican ključ ali deaktivirano podjetje vrne 401 invalid_key.

    Endpointi

    Osnovni URL: https://<project>.supabase.co/functions/v1/api-v1 (v primerih spodaj $BASE). Uspešen odgovor ima obliko {"data": [...]}; seznami podpirajo paginacijo z ?limit= (1–100, privzeto 50) in ?offset=.

    MetodaPotScopeOpis
    GET/work-hourswork_hours:readDelovni čas podjetja (7 vrstic, day_of_week 0 = ponedeljek … 6 = nedelja).
    GET/servicesservices:readAktivne storitve: id, name, price, duration_minutes.
    POST/inquiriesinquiries:writeUstvari povpraševanje v CRM (brez captche — zahtevek je avtenticiran s ključem).
    GET/invoicesinvoices:readGlave dokumentov (brez postavk): številka, datumi, znesek, status, stranka, plačilni podatki. Filtri: status, document_type, from/to, external_ref.
    POST/ordersorders:writeProdajno naročilo iz zunanjega sistema (spletna trgovina): najde ali ustvari stranko, po želji projekt, in izda predračun s sklicem SI00 in UPN QR; strežniški PDF (pdf_url, 30 dni) in ob send_email pošiljanje stranki. Zahteva funkcijo paketa ORDERS_API.
    GET/bookingsbookings:readJavne rezervacije s podatki o stranki in storitvah. Filtra from/to (po datumu rezervacije).

    Primer: delovni čas

    curl -H "Authorization: Bearer pe_live_..." \
      "$BASE/work-hours"
    
    # Odgovor:
    {"data": [{"day_of_week": 0, "is_open": true, "open_time": "08:00:00",
      "close_time": "20:00:00", "break_start": "12:00:00", "break_end": "13:00:00"}]}

    Primer: novo povpraševanje

    Obvezni polji sta name in description, plus vsaj eden od phone / email. Opcijsko: serviceType, source in gdprConsent (ob true se zabeleži čas privolitve).

    curl -X POST -H "Authorization: Bearer pe_live_..." \
      -H "Content-Type: application/json" \
      -d '{"name":"Janez Novak","phone":"041123456","description":"Ponudba za ograjo","gdprConsent":true}' \
      "$BASE/inquiries"
    
    # Odgovor (201):
    {"data": {"id": "...", "created_at": "..."}}

    Primer: naročilo iz spletne trgovine → predračun

    Strežnik zneske preračuna sam (odjemalčevi totals so le kontrola), stranko poišče po DDV številki ali e-pošti, predračun dobi številko iz vašega številčenja. Isti Idempotency-Key z istim telesom vrne isti dokument (brez podvajanja). Celotna pogodba: docs/specs/2026-09-orders-api.md.

    curl -X POST -H "Authorization: Bearer pe_live_..." \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: order-8f1c2d3e-v1" \
      -d '{
        "external_ref": "8f1c2d3e", "external_source": "trgovina",
        "client": { "name": "Avtohiša Novak d.o.o.", "customer_type": "business",
                    "vat_number": "SI12345678", "email": "narocila@novak.si",
                    "address": "Cesta 1", "postal_code": "1000", "city": "Ljubljana" },
        "items": [ { "description": "Kartonska podloga", "quantity": 100, "unit": "kos",
                     "unit_price": 0.85, "vat_rate": 22, "item_type": "material" } ],
        "create_project": true
      }' \
      "$BASE/orders"
    
    # Odgovor (201):
    {"data": {"invoice_id": "...", "document_number": "PF-2026/09/012", "status": "issued",
      "issue_date": "2026-09-15", "due_date": "2026-09-23", "valid_until": "2026-09-30",
      "totals": {"subtotal": 85.00, "total_vat": 18.70, "total": 103.70, "currency": "EUR"},
      "payment": {"iban": "SI56...", "reference": "SI00 0202-6090-12",
                  "purpose": "Plačilo po predračunu PF-2026/09/012", "amount": 103.70,
                  "upn_qr_payload": "UPNQR\n..."}}}

    Rate limiti

    60 / min

    Minutni limit na ključ. Ob prekoračitvi: 429, Retry-After: 60, koda rate_limited.

    1000 / dan

    Dnevni limit na ključ. Ob prekoračitvi: 429, Retry-After: 3600, koda rate_limited_day.

    V kvoto se štejejo samo postreženi zahtevki — zavrnjeni z 429 se ne štejejo.

    Webhooki

    ProEntry lahko vaš sistem obvešča o dogodkih s HTTP POST klicem na vaš https:// URL (privatni in lokalni naslovi so blokirani). Ob kreiranju naročnine prejmete secret oblike pe_whsec_<32 hex znakov> — prikazan je samo enkrat in ga kasneje ni mogoče ponovno prebrati. Vaš endpoint mora v 10 sekundah vrniti status 2xx; redirectom ne sledimo.

    Dogodki

    DogodekOpis
    inquiry.createdNovo povpraševanje (ime, kontakt, opis, vir).
    booking.createdNova javna rezervacija (termin, storitve, cena, stranka).
    booking.cancelledPreklic rezervacije (termin, čas in razlog preklica).
    invoice.paidRačun označen kot plačan (številka, znesek, stranka, datum plačila). Samo fiskalni dokumenti — ne za predračune/ponudbe.
    proforma.paidPredračun v celoti plačan (evidentiran prejeti avans): številka, external_source/external_ref, znesek, valuta, paid_at, način plačila, advance_payment_id.
    proforma.createdNov predračun (tudi iz POST /orders): številka, external_source/external_ref, znesek, roki, source_channel.
    pingTestni dogodek ob preizkusu naročnine — podpisan enako kot pravi dogodki.

    Oblika dostave

    Vsaka dostava je POST z JSON ovojnico. Isti dogodek lahko ob retryju prejmete večkrat — deduplicirajte po id dostave. Vrstni red dostav ni zagotovljen.

    POST <vaš URL>
    Content-Type: application/json
    X-ProEntry-Event: inquiry.created
    X-ProEntry-Delivery: 9c5e6d1e-...
    X-ProEntry-Signature: t=1755856800,v1=5f8a...
    User-Agent: ProEntry-Webhooks/1.0
    
    {
      "id": "9c5e6d1e-...",          // unikaten ID dostave (za deduplikacijo)
      "event": "inquiry.created",    // tip dogodka
      "created_at": "2026-08-22T10:00:00Z",
      "data": { ... }                // payload dogodka
    }

    Preverjanje podpisa

    Header X-ProEntry-Signature ima obliko t=<unix_ts>,v1=<hex>, kjer je v1 HMAC-SHA256 s secretom nad nizom "<unix_ts>.<surovo telo zahtevka>". Podpis vedno preverite nad surovim telesom (pred JSON parse), primerjajte s konstantno-časovno primerjavo in zavrnite zahtevke, kjer je razlika med t in trenutnim časom večja od npr. 5 minut (zaščita pred replay napadi).

    const crypto = require("node:crypto");
    
    function verifyProEntrySignature(rawBody, signatureHeader, secret, toleranceSec = 300) {
      const parts = Object.fromEntries(
        signatureHeader.split(",").map((p) => p.split("=", 2))
      );
      const ts = parseInt(parts.t, 10);
      if (!ts || !parts.v1) return false;
      if (Math.abs(Date.now() / 1000 - ts) > toleranceSec) return false;
    
      const expected = crypto
        .createHmac("sha256", secret)
        .update(`${ts}.${rawBody}`)
        .digest("hex");
      const a = Buffer.from(expected, "hex");
      const b = Buffer.from(parts.v1, "hex");
      return a.length === b.length && crypto.timingSafeEqual(a, b);
    }
    
    // Express: uporabite express.raw({ type: "application/json" }), da dobite surovo telo
    app.post("/webhooks/proentry", express.raw({ type: "application/json" }), (req, res) => {
      const ok = verifyProEntrySignature(
        req.body.toString("utf8"),
        req.get("X-ProEntry-Signature") || "",
        process.env.PROENTRY_WEBHOOK_SECRET
      );
      if (!ok) return res.status(401).end();
      const event = JSON.parse(req.body);
      // ... obdelava; deduplicirajte po event.id
      res.status(200).end();
    });

    Retry politika

    • Dostave obdeluje worker, ki teče vsako minuto — prva dostava tipično do ~1 minuto po dogodku.
    • Neuspela dostava (ne-2xx, timeout, napaka povezave) se ponovi z eksponentnim backoffom min(1 min × 2^poskus, 1 h): ~2 min, 4 min, 8 min, 16 min, 32 min, nato 1 h.
    • Največ 8 poskusov na dostavo; potem je dostava označena kot neuspešna in se ne ponavlja več.
    • Po 20 zaporednih neuspelih poskusih se naročnina samodejno deaktivira. Po odpravi napake jo znova vklopite; dogodki, nastali med deaktivacijo, se ne dostavijo za nazaj.

    Napake

    Vsaka napaka API-ja vrne JSON telo z opisom in strojno berljivo kodo:

    {"error": "<sporočilo>", "code": "<koda>"}
    StatusKodaKdaj
    401invalid_keyManjkajoč, neveljaven ali preklican ključ; tudi deaktivirano podjetje.
    403insufficient_scopeKljuč nima scope-a, ki ga endpoint zahteva.
    404not_foundNeznana pot.
    405method_not_allowedNapačna HTTP metoda za endpoint.
    429rate_limited / rate_limited_dayPresežen minutni oz. dnevni limit — glej Rate limiti.
    400validacijske kodeNeveljavno telo zahtevka (npr. manjkajoča obvezna polja pri POST /inquiries; validation_error s poljem field pri POST /orders).
    402iban_missingPOST /orders: podjetje nima vpisanega IBAN-a, zato predračuna s plačilnimi podatki ni mogoče izdati.
    403upgrade_requiredPOST /orders: paket ne vključuje funkcije ORDERS_API.
    409idempotency_conflict / external_ref_existsPOST /orders: isti Idempotency-Key z drugim telesom oz. odprt dokument za to naročilo že obstaja (telo vsebuje invoice_id).
    422totals_mismatch / vat_invalidPOST /orders: podani zneski odstopajo od strežniškega izračuna oz. DDV stopnje niso skladne z ZDDV-1.
    503not_readyEndpoint na tem okolju še ni omogočen — poskusite kasneje.
    500server_errorNapaka na strežniku — zahtevek ponovite kasneje.

    Pripravljen za začetek?

    Preizkusite ProEntry brezplačno in odkrijte, kako lahko poenostavite svoje poslovanje.

    Pišite nam

    Kontakt

    E-pošta
    info@proentry.si
    Delovni čas
    Pon - Pet: 8:00 - 16:00