Fiziksel POS
API Referansı
Mağazalar

Mağazalar

Bu uçları kim çağırır?Dış API (s2s)
Taban yol
/api/v1/physical-pos
Kimlik
Her istekte Ed25519 istek imzası — X-Key-Id, X-Date, X-Nonce, X-Signature; gövdeli isteklerde ayrıca Digest. Zaman penceresi ±5 dk, nonce tek kullanımlık. Bearer jetonu ya da panel oturumu bu uçlarda kabul edilmez.
Yetki
Anahtarınız Fiziksel POS ürününü (PHYSICAL_POS) ve bu sayfadaki uçların kapsamını taşımalıdır: physical_pos:view · physical_pos:manage. Ürünü olmayan anahtar 403 PRODUCT_NOT_ENABLED, kapsamı olmayan anahtar 403 API_INSUFFICIENT_SCOPE alır. Bkz. Kimlik Doğrulama ve Kapsamlar.
Çapraz yüzey
Bu uçlar s2s yüzeyindedir; kendi sunucunuzdan imzalı istekle çağırırsınız. Aynı kayıtların panelde ekranları var, ama panel uçları API anahtarıyla çağrılamaz; bu uçlar da panel oturumuyla çağrılamaz.

Mağaza, işletmenizin bir satış noktasıdır. Kasalar mağazaya bağlıdır: → Kasalar. Mağazalar ortamsızdır; test anahtarı mağazaları yalnız okuyabilir, yazma uçları test anahtarıyla 403 physical_pos.environment.test_key_read_only alır. → Ortamlar

YöntemYolKapsam
GET/api/v1/physical-pos/storesphysical_pos:view
POST/api/v1/physical-pos/storesphysical_pos:manage
GET/api/v1/physical-pos/stores/{storeId}physical_pos:view
PATCH/api/v1/physical-pos/stores/{storeId}physical_pos:manage
POST/api/v1/physical-pos/stores/{storeId}/archivephysical_pos:manage
POST/api/v1/physical-pos/stores/{storeId}/restorephysical_pos:manage
GET/api/v1/physical-pos/stores/{storeId}/auditphysical_pos:view

cURL örnekleri imzayı lunixi-sign.sh ile hesaplar: Kimlik Doğrulama › İmza yardımcısı.

Mağaza nesnesi

AlanTipAçıklama
idstring (UUID)Mağazanın kimliği.
codestringMağaza kodu; büyük harfli, organizasyonunuzda tekil. Oluşturulduktan sonra değişmez.
namestringMağaza adı.
citystring | nullŞehir.
districtstring | nullİlçe.
addressLinestring | nullAdres satırı.
timezonestringIANA saat dilimi, ör. Europe/Istanbul.
storeStatusstringACTIVE ya da ARCHIVED.
externalRefstring | nullKendi sisteminizdeki mağaza kimliği; organizasyonunuzda tekil.
rowVersionintegerEşzamanlılık sürümü. → rowVersion
createdAtstringOluşturulma zamanı.
updatedAtstringSon değişiklik zamanı.

Mağazaları listeleme

GET /api/v1/physical-pos/stores

Sorgu parametresiTipAçıklama
statusstringACTIVE ya da ARCHIVED. Gönderilmezse ikisi de döner. Başka değer 400 physical_pos.input.filter_invalid.
qstringMağaza kodunun ya da adının başıyla eşleşen kayıtlar, en çok 64 karakter.
limitintegerSayfa başına kayıt, 1–100. Varsayılan 25.
cursorstringÖnceki yanıttaki pageInfo.nextCursor.
includeTotalbooleantrue ise pageInfo.totalCount doldurulur.

Liste satırları mağaza nesnesinin alanlarına ek olarak registerCount (mağazanın aktif kasa sayısı) taşır.

source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/stores?status=ACTIVE&q=IST&limit=50"
lunixi_sign GET "$REQ_PATH"
 
curl "https://api-gateway.lunixi.com$REQ_PATH" \
  -H "X-Key-Id: $LUNIXI_KEY_ID" \
  -H "X-Date: $DATE" \
  -H "X-Nonce: $NONCE" \
  -H "X-Signature: $SIGNATURE"
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "items": [
      {
        "id": "00000000-0000-0000-0000-000000000101",
        "code": "IST-KADIKOY",
        "name": "Kadıköy Mağazası",
        "city": "İstanbul",
        "district": "Kadıköy",
        "addressLine": "Örnek Cad. No: 1",
        "timezone": "Europe/Istanbul",
        "storeStatus": "ACTIVE",
        "externalRef": "store_00042",
        "rowVersion": 2,
        "createdAt": "2026-01-01T07:00:00.000Z",
        "updatedAt": "2026-01-05T09:30:00.000Z",
        "registerCount": 3
      }
    ],
    "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null }
  },
  "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null },
  "statusCode": 200,
  "requestId": "00000000-0000-0000-0000-000000000000"
}

Mağaza oluşturma

POST /api/v1/physical-pos/stores · Idempotency-Key zorunlu

AlanTipZorunluAçıklama
codestringEvetMağaza kodu: A-Z, 0-9, ., _, -; en çok 64 karakter. Büyük harfe çevrilir. → Kod kuralları
namestringEvetMağaza adı, en çok 200 karakter.
citystringHayırŞehir, en çok 100 karakter.
districtstringHayırİlçe, en çok 100 karakter.
addressLinestringHayırAdres satırı, en çok 300 karakter.
timezonestringHayırIANA saat dilimi. Varsayılan Europe/Istanbul. → Saat dilimi
externalRefstringHayırKendi sisteminizdeki kimlik: boşluksuz yazdırılabilir ASCII, en çok 128 karakter. Olduğu gibi saklanır.

Serbest metin alanları metin kurallarına tabidir.

source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/stores"
BODY='{"code":"ist-kadikoy","name":"Kadıköy Mağazası","city":"İstanbul","district":"Kadıköy","addressLine":"Örnek Cad. No: 1","externalRef":"store_00042"}'
lunixi_sign POST "$REQ_PATH" "$BODY"
 
curl -X POST "https://api-gateway.lunixi.com$REQ_PATH" \
  -H "Content-Type: application/json" \
  -H "X-Key-Id: $LUNIXI_KEY_ID" \
  -H "X-Date: $DATE" \
  -H "X-Nonce: $NONCE" \
  -H "Digest: $DIGEST" \
  -H "X-Signature: $SIGNATURE" \
  -H "Idempotency-Key: 4f9b2c1e-0000-4000-8000-000000000001" \
  --data-raw "$BODY"

Yeni mağazada 201, aynı anahtar ve aynı gövdeyle tekrarda 200 ve replayed: true döner:

{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "store": {
      "id": "00000000-0000-0000-0000-000000000101",
      "code": "IST-KADIKOY",
      "name": "Kadıköy Mağazası",
      "city": "İstanbul",
      "district": "Kadıköy",
      "addressLine": "Örnek Cad. No: 1",
      "timezone": "Europe/Istanbul",
      "storeStatus": "ACTIVE",
      "externalRef": "store_00042",
      "rowVersion": 1,
      "createdAt": "2026-01-01T07:00:00.000Z",
      "updatedAt": "2026-01-01T07:00:00.000Z"
    },
    "replayed": false
  },
  "statusCode": 201,
  "requestId": "00000000-0000-0000-0000-000000000000"
}

Mağaza kodu ve externalRef arşivli mağazalar dahil tekildir: arşivlediğiniz bir mağazanın kodunu yeni mağazada kullanamazsınız. Mağazayı yeniden kullanmak istiyorsanız yeniden açın.

Mağaza ayrıntısı

GET /api/v1/physical-pos/stores/{storeId}

{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "store": {
      "id": "00000000-0000-0000-0000-000000000101",
      "code": "IST-KADIKOY",
      "name": "Kadıköy Mağazası",
      "city": "İstanbul",
      "district": "Kadıköy",
      "addressLine": "Örnek Cad. No: 1",
      "timezone": "Europe/Istanbul",
      "storeStatus": "ACTIVE",
      "externalRef": "store_00042",
      "rowVersion": 2,
      "createdAt": "2026-01-01T07:00:00.000Z",
      "updatedAt": "2026-01-05T09:30:00.000Z"
    },
    "registerSummary": { "activeCount": 3, "archivedCount": 1 },
    "assignedDeviceCount": 0
  },
  "statusCode": 200,
  "requestId": "00000000-0000-0000-0000-000000000000"
}
AlanAçıklama
storeMağaza nesnesi.
registerSummary.activeCountAktif kasa sayısı.
registerSummary.archivedCountArşivli kasa sayısı.
assignedDeviceCountMağazaya (ve kasalarına) atanmış cihaz sayısı.

Olmayan, başka bir organizasyona ait ya da biçim dışı kimlik 404 physical_pos.store.not_found döner.

Mağaza güncelleme

PATCH /api/v1/physical-pos/stores/{storeId}

AlanTipZorunluAçıklama
rowVersionintegerEvetSon okuduğunuz rowVersion.
namestringHayırYeni ad.
citystring | nullHayırnull alanı temizler.
districtstring | nullHayırnull alanı temizler.
addressLinestring | nullHayırnull alanı temizler.
timezonestringHayırYeni IANA saat dilimi.
externalRefstring | nullHayırnull alanı temizler.
  • Gönderilmeyen alan değişmez. code değiştirilemez; gövdede code gönderilirse 400 VALIDATION_ERROR.
  • Değişecek alan içermeyen istek 400 physical_pos.input.empty_patch alır.
  • Gönderilen değerler mevcut değerlerle aynıysa kayıt değişmez, rowVersion artmaz ve değişiklik geçmişine olay yazılmaz.
  • Arşivli mağaza güncellenemez: 409 physical_pos.store.archived. Önce yeniden açın.
source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/stores/00000000-0000-0000-0000-000000000101"
BODY='{"rowVersion":2,"name":"Kadıköy Moda Mağazası","addressLine":null}'
lunixi_sign PATCH "$REQ_PATH" "$BODY"
 
curl -X PATCH "https://api-gateway.lunixi.com$REQ_PATH" \
  -H "Content-Type: application/json" \
  -H "X-Key-Id: $LUNIXI_KEY_ID" \
  -H "X-Date: $DATE" \
  -H "X-Nonce: $NONCE" \
  -H "Digest: $DIGEST" \
  -H "X-Signature: $SIGNATURE" \
  --data-raw "$BODY"

Yanıt: { "store": { … } } — güncel mağaza nesnesi, yeni rowVersion ile.

Mağaza arşivleme

POST /api/v1/physical-pos/stores/{storeId}/archive

AlanTipZorunluAçıklama
rowVersionintegerEvetSon okuduğunuz rowVersion.
reasonCodestringEvetSTORE_CLOSED, TEMPORARILY_CLOSED, RELOCATED, MERGED, CREATED_IN_ERROR, DATA_CORRECTION, OTHER. → Gerekçe kodları

Mağaza arşivlendiğinde aktif kasaları da aynı işlemde arşivlenir. Yanıt, arşivlenen kasa sayısını da verir:

source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/stores/00000000-0000-0000-0000-000000000101/archive"
BODY='{"rowVersion":3,"reasonCode":"STORE_CLOSED"}'
lunixi_sign POST "$REQ_PATH" "$BODY"
 
curl -X POST "https://api-gateway.lunixi.com$REQ_PATH" \
  -H "Content-Type: application/json" \
  -H "X-Key-Id: $LUNIXI_KEY_ID" \
  -H "X-Date: $DATE" \
  -H "X-Nonce: $NONCE" \
  -H "Digest: $DIGEST" \
  -H "X-Signature: $SIGNATURE" \
  --data-raw "$BODY"
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "store": {
      "id": "00000000-0000-0000-0000-000000000101",
      "code": "IST-KADIKOY",
      "storeStatus": "ARCHIVED",
      "rowVersion": 4
    },
    "archivedRegisterCount": 3
  },
  "statusCode": 200,
  "requestId": "00000000-0000-0000-0000-000000000000"
}

Örnekte mağaza nesnesi kısaltılmıştır; yanıt bütün alanları içerir.

EngelHata
Mağazaya ya da kasalarından birine atanmış cihaz var409 physical_pos.store.has_devices — cihazları başka mağazaya taşıyın, depoya alın ya da emekliye ayırın.
Mağazanın 200'den fazla aktif kasası var409 physical_pos.store.too_many_active_registers (details.limit: 200) — önce kasaları tek tek arşivleyin.
Mağaza zaten arşivli409 physical_pos.store.invalid_transition

Mağazayı yeniden açma

POST /api/v1/physical-pos/stores/{storeId}/restore

AlanTipZorunluAçıklama
rowVersionintegerEvetSon okuduğunuz rowVersion.
reasonCodestringEvetREOPENED, ARCHIVED_IN_ERROR, DATA_CORRECTION, OTHER.

Arşivli mağaza ACTIVE olur; kodu ve externalRef değeri korunur. Kasalar arşivli kalır; ihtiyacınız olanları tek tek yeniden açın. Mağaza zaten aktifse 409 physical_pos.store.invalid_transition.

Yanıt: { "store": { … } }.

Değişiklik geçmişi

GET /api/v1/physical-pos/stores/{storeId}/audit

Sorgu parametresiTipAçıklama
limitintegerSayfa başına olay, 1–100. Varsayılan 25.
cursorstringÖnceki yanıttaki pageInfo.nextCursor.
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "items": [
      {
        "id": "00000000-0000-0000-0000-000000000901",
        "action": "physical_pos.audit.store_updated",
        "actorType": "API_KEY",
        "actorId": "kid:mk_live_00000000",
        "reasonCode": null,
        "changes": {
          "storeId": "00000000-0000-0000-0000-000000000101",
          "storeNo": "IST-KADIKOY",
          "nameChanged": true
        },
        "requestId": "00000000-0000-0000-0000-000000000000",
        "createdAt": "2026-01-05T09:30:00.000Z"
      }
    ],
    "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null }
  },
  "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null },
  "statusCode": 200,
  "requestId": "00000000-0000-0000-0000-000000000000"
}

Mağaza olayları: physical_pos.audit.store_created, …store_updated, …store_archived, …store_restored. Alanların anlamı: Ortak Kurallar › Değişiklik geçmişi.

Hatalar

HTTPcodeNe zaman
400physical_pos.idempotency.key_required / physical_pos.idempotency.key_invalidOluşturmada Idempotency-Key yok ya da biçim dışı.
400physical_pos.input.code_invalidcode biçim dışı.
400physical_pos.input.text_invalidSerbest metin kurala uymuyor.
400physical_pos.input.ref_invalidexternalRef biçim dışı.
400physical_pos.input.reason_code_invalidreasonCode listede yok ya da işleme uymuyor.
400physical_pos.validation.invalidTanınmayan saat dilimi.
400physical_pos.input.empty_patchBoş güncelleme.
400physical_pos.cursor.invalidBozuk imleç.
400physical_pos.input.filter_invalidListe süzgeci geçersiz.
403physical_pos.environment.test_key_read_onlyYazma isteği test anahtarıyla yapıldı.
404physical_pos.store.not_foundMağaza yok ya da size ait değil.
409physical_pos.store.code_takenKod kullanımda (arşivli mağazalar dahil).
409physical_pos.store.external_ref_takenexternalRef kullanımda (arşivli mağazalar dahil).
409physical_pos.store.archivedArşivli mağaza güncellenmek istendi.
409physical_pos.store.has_devicesCihaz atanmış mağaza arşivlenmek istendi.
409physical_pos.store.too_many_active_registersAktif kasa sayısı tek seferde arşivleme sınırını aşıyor.
409physical_pos.store.invalid_transitionArşivli mağazayı arşivleme ya da aktif mağazayı yeniden açma.
409physical_pos.version_conflictrowVersion güncel değil.
409physical_pos.idempotency_mismatchAynı Idempotency-Key farklı bir istekle kullanılmış.
429RATE_LIMITEDMağaza ve kasa yazma sınırı aşıldı. → Oran sınırı

Bütün kodlar: Hata Kodları.