Fiskaliza

Fillimi

Nga çelësi API te shitja e parë e fiskalizuar dhe kuponi i lëshuar — katër kërkesa HTTP.

Ky udhëzues të çon nga një çelës API te një kupon fiskal i lëshuar. Të gjithë shembujt përdorin cURL.

Çfarë të duhet paraprakisht

Një çelës API Fiskaliza (fsk_test_… për fillim), URL-ja bazë e deployment-it tënd, numri i fiskalizimit i pikës së shitjes (fiscalization_no) dhe numri i njësisë i regjistruar te ATK (branch_id) nga regjistrimi i biznesit.

Nëse ende nuk ke çelës, shih si merret një çelës.

setup.sh
export BASE_URL="http://fiskaliza.localhost/api"
export FISKALIZA_API_KEY="fsk_test_…"

Regjistro pikën e shitjes

Fiskaliza e nxjerr biznesin nga çelësi dhe gjeneron vetë aliasin publik, identifikuesin e operatorit dhe identifikuesit ATK të degës, POS-it dhe aplikacionit.

1-pos.sh
curl -X POST "$BASE_URL/v1/pos" \
  -H "Authorization: Bearer $FISKALIZA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pos-main-till-01" \
  -d '{
    "fiscalization_no": "601234567",
    "branch_id": 1,
    "vat_number": "330123456",
    "address": {
      "line_1": "Bulevardi Nene Tereza 1",
      "city": "Prishtina",
      "country": "XK",
      "phone": "+383 38 123 456"
    },
    "timezone": "Europe/Belgrade",
    "default_operator": { "name": "Ana" }
  }'

address.phone është i detyrueshëm sepse printohet në çdo kupon fiskal si TELEFONI.

Përgjigja mbështjell POS-in:

{
  "success": true,
  "data": {
    "pos": {
      "id": "nj_pos_7f3c1a2b",
      "legal_name": "…",
      "operating_profile": "GENERAL_RETAIL",
      "status": "…"
    }
  }
}
export POS_ID="nj_pos_7f3c1a2b"

Kjo rrugë kërkon një çelës me akses ALL te POS-et — një çelës SELECTED nuk mund ta zgjerojë vetë fushëveprimin. fiscalization_no është writeOnly dhe nuk kthehet kurrë në asnjë përgjigje.

branch_id është numri i njësisë i regjistruar te ATK. Printohet në çdo kupon dhe nënshkruhet në identifikuesin SEF, dhe ATK e kontrollon kundrejt fiscalization_no gjatë onboarding-ut të POS-it — një çift i paregjistruar dështon. pos_id numëron arkën brenda asaj njësie dhe merr si parazgjedhje numrin e parë të papërdorur, prandaj hiqe nëse nuk po përputh një strukturë ekzistuese arkash.

Lësho shitjen e parë

Çdo lloj komande ka rrugën e vet, prandaj dërgimi te /sales është ajo që e bën këtë një shitje. Të gjitha shumat janë në EUR.

2-sale.sh
curl -X POST "$BASE_URL/v1/pos/$POS_ID/sales" \
  -H "Authorization: Bearer $FISKALIZA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: sale-order_123" \
  -d '{
    "external_id": "order_123",
    "occurred_at": "2026-08-26T10:00:00+02:00",
    "items": [
      { "name": "Coffee", "unit_price_cents": 118, "tax_category": "E" }
    ],
    "payments": [ { "type": "CASH" } ]
  }'

Kaq mjafton për një shitje. Pjesën tjetër e plotëson Fiskaliza:

  • shumat e rreshtave dhe totalet e kuponit, të llogaritura nga çmimi dhe sasia;
  • grupet e taksave, të nxjerra nga tax_category e çdo rreshti;
  • shuma e pagesës — me një pagesë të vetme është totali i llogaritur.

unit_price_cents: 118 do të thotë EUR 1.18, me TVSH të përfshirë. Kategoria E është norma standarde 18%.

Përgjigja është 201 me komandën dhe dokumentin e kuponit të lëshuar për të:

{
  "success": true,
  "data": {
    "command": {
      "id": "command_123",
      "pos_id": "nj_pos_7f3c1a2b",
      "external_id": "order_123",
      "type": "SALE",
      "status": "PENDING",
      "attempt_count": 0,
      "receipt_ready": false,
      "created_at": "2026-08-26T10:00:01Z"
    },
    "receipt_document": {
      "id": "doc_123",
      "kind": "ORIGINAL",
      "locale": "sq",
      "pdf_url": "/v1/receipt-documents/doc_123/pdf",
      "pdf_sha256": "…"
    }
  }
}

PDF-ja ORIGINAL lëshohet vetvetiu — nuk ka thirrje të veçantë për të bërë. Shto ?locale=en te shitja për ta rendëruar në një gjuhë tjetër. Një komandë e refuzuar ka receipt_document: null.

external_id është referenca jote për transaksionin dhe kthehet e pandryshuar. Brenda një POS-i ajo është edhe çelës deduplikimi: një kërkesë që përputhet ripërsërit komandën ekzistuese, edhe me një Idempotency-Key tjetër.

export COMMAND_ID="command_123"

Prit derisa kuponi të jetë gati

Komanda krijohet PENDING dhe përpunohet asinkronisht.

3-poll.sh
curl "$BASE_URL/v1/commands/$COMMAND_ID" \
  -H "Authorization: Bearer $FISKALIZA_API_KEY"

Lexo derisa receipt_ready të bëhet true. Kur komanda ka sukses, ajo mban edhe objektin coupon:

{
  "success": true,
  "data": {
    "command": {
      "status": "SUCCEEDED",
      "receipt_ready": true,
      "issuance_mode": "ONLINE",
      "coupon": {
        "coupon_id": 41,
        "daily_receipt_no": 12,
        "verification_no": "…",
        "qr_payload": "…",
        "issued_at": "2026-08-26T10:00:04Z"
      }
    }
  }
}

Vizato kodin QR nga qr_payload.

OFFLINE nuk është dështim

issuance_mode: "OFFLINE" do të thotë se kuponi u lëshua me certifikatën lokale dhe transmetimi te ATK është ende në pritje. Shitja është e vlefshme.

Shkarko kuponin

ORIGINAL-i u kthye bashkë me shitjen, prandaj nuk ka çfarë të lëshosh. Merr id-në e tij nga receipt_document dhe shkarko bajtat:

4-receipt.sh
curl "$BASE_URL/v1/receipt-documents/$DOCUMENT_ID/pdf" \
  -H "Authorization: Bearer $FISKALIZA_API_KEY" \
  -o kupon.pdf

Verifiko bajtat kundrejt pdf_sha256 nëse i arkivon. Nëse klientit i duhet më vonë edhe një, lësho një COPY.

Një shembull më i plotë

Sasi dhjetore, zbritje rreshti, njësi të qarta dhe pagesa të ndara:

{
  "external_id": "order_restaurant_88",
  "occurred_at": "2026-08-25T20:15:00+02:00",
  "operator": { "name": "Blerim" },
  "items": [
    { "line_id": "line_2", "name": "Pizza Margherita", "unit_price_cents": 650, "quantity": 2, "tax_category": "E" },
    { "name": "Ujë 0.5L", "unit_price_cents": 100, "quantity": 3, "tax_category": "D" },
    { "name": "Tarifë shërbimi", "unit": "service", "type": "SERVICE", "unit_price_cents": 200, "discount_cents": 50, "tax_category": "E" }
  ],
  "payments": [{ "type": "CREDIT_CARD" }]
}

Rreshtat pa line_id marrin automatikisht line_1, line_2, … duke kapërcyer çdo ID të dhënë shprehimisht. Ruaji këto ID nëse mendon të bësh kthime më vonë.

Hapat e mëpasshëm