Fiziksel POS
API Referansı
Cihazlar

Cihazlar

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.

Cihaz, mağazalarınızdaki fiziksel POS donanımıdır: üreticisi, katalogdaki modeli ve seri numarası olan kayıt. Cihazı bir mağazaya (ve isteğe bağlı olarak bir kasaya) atarsınız; bir mantıksal terminale bağlamak için cihazın id değerini cihaz bağı uçlarında deviceId olarak kullanırsınız. → Temel kavramlar

Cihazlar anahtarınızın ortamındadır; diğer ortamın cihazı 404 döner. Test anahtarı cihazları yalnız okur. → Ortamlar

YöntemYolKapsam
GET/api/v1/physical-pos/devicesphysical_pos:view
POST/api/v1/physical-pos/devicesphysical_pos:manage
GET/api/v1/physical-pos/devices/{deviceId}physical_pos:view
PATCH/api/v1/physical-pos/devices/{deviceId}physical_pos:manage
POST/api/v1/physical-pos/devices/{deviceId}/assignmentphysical_pos:manage
POST/api/v1/physical-pos/devices/{deviceId}/assignment/closephysical_pos:manage
POST/api/v1/physical-pos/devices/{deviceId}/retirephysical_pos:manage
GET/api/v1/physical-pos/devices/{deviceId}/assignmentsphysical_pos:view
GET/api/v1/physical-pos/devices/{deviceId}/auditphysical_pos:view

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

Cihaz nesnesi

Liste satırları aşağıdaki özet alanları taşır; ayrıntı ve yazma yanıtları özet alanlarına ek olarak ayrıntı alanlarını taşır.

AlanTipAçıklama
idstring (UUID)Cihazın kimliği; cihaz bağında deviceId olarak kullanılır.
displayNamestring | nullGörünen ad.
vendorCodestringÜretici kodu (ör. PAVO).
modelIdstring (UUID)Katalogdaki modelin kimliği.
modelDisplayNamestringModelin adı.
modelImageobject | nullModelin görseli, { assetId, url }. → Görsel nesnesi
vendorFallbackImageobject | nullÜreticinin yedek görseli.
deviceTypestringPHYSICAL ya da SOFTPOS.
formFactorstringCOUNTERTOP, PORTABLE, MOBILE, UNATTENDED ya da PINPAD.
serialNumberstringSeri numarası, kaydettiğiniz biçimde.
environmentstringTEST ya da LIVE; anahtarınızın ortamı.
lifecycleStatusstringPENDING, ACTIVE, SUSPENDED, MAINTENANCE ya da RETIRED. Yeni kaydedilen cihaz PENDING durumundadır.
ownershipStatusstringUNVERIFIED: cihazın size ait olduğu doğrulanmadı. VERIFIED: doğrulandı. Yeni kaydedilen cihaz UNVERIFIED durumundadır.
integrationChannelstringCihazla haberleşme kanalı: APP2APP, LOCAL_REST, VENDOR_CLOUD ya da UNSET.
appModestring | nullCihazdaki uygulamanın modu: BRIDGE, CASHIER, KIOSK, MINIBUS ya da TAXI. Yalnız APP2APP ve LOCAL_REST kanalında.
storeobject | nullAtandığı mağaza { id, code, name }; depodaysa null.
registerobject | nullAtandığı kasa { id, code, name }.
logicalTerminalobject | nullBağlı olduğu terminal { id, code }.
createdAtstringOluşturulma zamanı.

Ayrıntı alanları

AlanTipAçıklama
vendorDeviceRefstringÜreticinin cihaza verdiği kimlik.
channelVariantstring | nullKanalın üreticiye özgü çeşidi.
externalRefstring | nullKendi sisteminizdeki cihaz kimliği.
hardwareManufacturerstring | nullDonanım üreticisi.
hardwareModelstring | nullDonanım modeli.
verifiedAtstring | nullSahipliğin doğrulandığı zaman.
verifiedViastring | nullDoğrulamanın kaynağı: ACTIVATION, VENDOR_ACCOUNT ya da OPERATOR.
vendorAccountobject | nullCihazın bağlı olduğu üretici hesabı { id, label }.
firstActivatedAtstring | nullCihazın ilk kez ACTIVE olduğu zaman.
retiredAtstring | nullEmekliye ayrıldığı zaman.
sourcestringKaydın kaynağı: MANUAL (panelden ya da API'den) ya da VENDOR_ACCOUNT.
fieldSourcesobjectAlan adı → o alanın kaynağı (MANUAL, VENDOR_ACCOUNT, DEVICE_REPORTED).
driftarrayKaynaklar arasında ayrışan alanlar; öğe biçimi { field, source, observedAt }.
activeKeyobject | nullCihazın etkin kimlik anahtarı { keyId, activatedAt }.
openActivationCodeobject | nullSüresi dolmamış açık aktivasyon kodu { expiresAt }. Kodun kendisi dönmez.
rowVersionintegerEşzamanlılık sürümü. → rowVersion
updatedAtstringSon değişiklik zamanı.

Cihazları listeleme

GET /api/v1/physical-pos/devices

Sorgu parametresiTipAçıklama
storeIdstring (UUID)Bu mağazaya atanmış cihazlar.
registerIdstring (UUID)Bu kasaya atanmış cihazlar.
vendorCodestringÜretici kodu.
deviceModelIdstring (UUID)Katalog modeli.
deviceTypestringPHYSICAL ya da SOFTPOS.
lifecycleStatusstringPENDING, ACTIVE, SUSPENDED, MAINTENANCE ya da RETIRED.
ownershipStatusstringUNVERIFIED ya da VERIFIED.
integrationChannelstringAPP2APP, LOCAL_REST, VENDOR_CLOUD ya da UNSET.
qstringSeri numarası, üretici kimliği, dış referans ya da görünen adın başıyla eşleşen cihazlar, en çok 64 karakter. Yalnız sizin cihazlarınızda arar.
limitintegerSayfa başına kayıt, 1–100. Varsayılan 25.
cursorstringÖnceki yanıttaki pageInfo.nextCursor.
includeTotalbooleantrue ise pageInfo.totalCount doldurulur.

Geçersiz süzgeç değeri (küme dışı durum, biçim dışı kimlik, bilinmeyen üretici kodu, kurala uymayan ya da 64 karakteri aşan q) 400 physical_pos.input.filter_invalid alır; details.field süzgecin adını verir. Değer kümeleri büyük/küçük harfe duyarlıdır.

source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/devices?storeId=00000000-0000-0000-0000-000000000101&lifecycleStatus=PENDING"
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-000000000401",
        "displayName": "Kasa 1 POS",
        "vendorCode": "PAVO",
        "modelId": "00000000-0000-4000-8000-000000000b01",
        "modelDisplayName": "Örnek Model M1",
        "modelImage": {
          "assetId": "00000000-0000-4000-8000-000000000a02",
          "url": "https://img.lunixi.com/00000000-0000-4000-8000-000000000a02"
        },
        "vendorFallbackImage": null,
        "deviceType": "PHYSICAL",
        "formFactor": "COUNTERTOP",
        "serialNumber": "SN0000000001",
        "environment": "LIVE",
        "lifecycleStatus": "PENDING",
        "ownershipStatus": "UNVERIFIED",
        "integrationChannel": "APP2APP",
        "appMode": "CASHIER",
        "store": { "id": "00000000-0000-0000-0000-000000000101", "code": "IST-KADIKOY", "name": "Kadıköy Mağazası" },
        "register": { "id": "00000000-0000-0000-0000-000000000201", "code": "KASA-1", "name": "Giriş Kasası" },
        "logicalTerminal": null,
        "createdAt": "2026-01-02T08:00:00.000Z"
      }
    ],
    "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null }
  },
  "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null },
  "statusCode": 200,
  "requestId": "00000000-0000-0000-0000-000000000000"
}

Cihaz kaydetme

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

AlanTipZorunluAçıklama
vendorCodestringEvetKatalogdaki etkin bir üreticinin kodu. → Katalog › Üreticiler
deviceModelIdstring (UUID)EvetAynı üreticinin etkin bir modeli. → Katalog › Cihaz modelleri
serialNumberstringEvetCihazın seri numarası; biçim üreticiye göre değişir, aşağıya bakın.
displayNamestringHayırGörünen ad, en çok 120 karakter. Metin kurallarına tabidir.
externalRefstringHayırKendi sisteminizdeki kimlik: boşluksuz yazdırılabilir ASCII, en çok 128 karakter. Ortamınızda tekildir.
storeIdstring (UUID)HayırVerilirse cihaz aynı işlemde bu mağazaya atanır (gerekçe INITIAL_SETUP).
registerIdstring (UUID)HayırMağazanın bir kasası; storeId olmadan gönderilemez.
integrationChannelstringEvetAPP2APP, LOCAL_REST, VENDOR_CLOUD ya da UNSET.
channelVariantstringHayırKanalın çeşidi: harfle başlar, A-Z, 0-9, _; en çok 32 karakter. Büyük harfe çevrilir.
appModestringHayırBRIDGE, CASHIER, KIOSK, MINIBUS ya da TAXI. Yalnız APP2APP ve LOCAL_REST kanalında.

Seri numarası biçimi:

ÜreticiKural
CASTLES12 ya da 16 rakam. 0000 ile başlayan 16 haneli seri, son 12 haneyle aynı cihaz sayılır.
PAVOA-Z ve 0-9, 4–64 karakter; büyük/küçük harf fark etmez.
PLUSPAYBoşluksuz yazdırılabilir ASCII, en çok 128 karakter; büyük/küçük harf korunur ve değer kırpılmaz.

Biçim dışı seri 400 physical_pos.input.serial_invalid alır. Seri numarası hesabınızda tekildir (üreticiden ve ortamdan bağımsız); aynı seriyle kayıtlı bir cihazınız varsa 409 physical_pos.device.serial_taken. Emekliye ayrılan cihazın serisi yeniden kaydedilebilir.

Yeni cihaz lifecycleStatus: "PENDING", ownershipStatus: "UNVERIFIED" ve source: "MANUAL" ile başlar.

source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/devices"
BODY='{"vendorCode":"PAVO","deviceModelId":"00000000-0000-4000-8000-000000000b01","serialNumber":"SN0000000001","displayName":"Kasa 1 POS","storeId":"00000000-0000-0000-0000-000000000101","registerId":"00000000-0000-0000-0000-000000000201","integrationChannel":"APP2APP","appMode":"CASHIER"}'
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-000000000006" \
  --data-raw "$BODY"

Yeni cihazda 201, aynı anahtar ve aynı gövdeyle tekrarda 200 döner. data: { "device": { … }, "replayed": false }; device ayrıntı biçimindedir.

EngelHata
Üretici katalogda yok ya da devre dışı400 physical_pos.device.vendor_unknown
Model yok404 physical_pos.device_model.not_found
Model başka üreticinin400 physical_pos.device.model_vendor_mismatch
Model kullanımdan kalkmış (DEPRECATED)409 physical_pos.device.model_deprecated
appMode bu kanalda kullanılamaz400 physical_pos.device.app_mode_invalid
registerId var, storeId yok400 physical_pos.validation.invalid
Mağaza ya da kasa yok, ya da kasa bu mağazanın değil404 physical_pos.store.not_found / 404 physical_pos.register.not_found
Mağaza ya da kasa arşivli409 physical_pos.store.archived / 409 physical_pos.register.archived
externalRef kullanımda409 physical_pos.device.external_ref_taken

Cihaz ayrıntısı

GET /api/v1/physical-pos/devices/{deviceId}

{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "device": {
      "id": "00000000-0000-0000-0000-000000000401",
      "displayName": "Kasa 1 POS",
      "vendorCode": "PAVO",
      "modelId": "00000000-0000-4000-8000-000000000b01",
      "modelDisplayName": "Örnek Model M1",
      "modelImage": null,
      "vendorFallbackImage": null,
      "deviceType": "PHYSICAL",
      "formFactor": "COUNTERTOP",
      "serialNumber": "SN0000000001",
      "environment": "LIVE",
      "lifecycleStatus": "PENDING",
      "ownershipStatus": "UNVERIFIED",
      "integrationChannel": "APP2APP",
      "appMode": "CASHIER",
      "store": { "id": "00000000-0000-0000-0000-000000000101", "code": "IST-KADIKOY", "name": "Kadıköy Mağazası" },
      "register": { "id": "00000000-0000-0000-0000-000000000201", "code": "KASA-1", "name": "Giriş Kasası" },
      "logicalTerminal": null,
      "createdAt": "2026-01-02T08:00:00.000Z",
      "vendorDeviceRef": "SN0000000001",
      "channelVariant": null,
      "externalRef": null,
      "hardwareManufacturer": null,
      "hardwareModel": null,
      "verifiedAt": null,
      "verifiedVia": null,
      "vendorAccount": null,
      "firstActivatedAt": null,
      "retiredAt": null,
      "source": "MANUAL",
      "fieldSources": { "displayName": "MANUAL" },
      "drift": [],
      "activeKey": null,
      "openActivationCode": null,
      "rowVersion": 1,
      "updatedAt": "2026-01-02T08:00:00.000Z"
    }
  },
  "statusCode": 200,
  "requestId": "00000000-0000-0000-0000-000000000000"
}

Olmayan, başka bir organizasyona ya da diğer ortama ait cihaz 404 physical_pos.device.not_found döner.

Cihaz güncelleme

PATCH /api/v1/physical-pos/devices/{deviceId}

AlanTipZorunluAçıklama
rowVersionintegerEvetSon okuduğunuz rowVersion.
displayNamestring | nullHayırnull alanı temizler.
externalRefstring | nullHayırnull alanı temizler.
integrationChannelstringHayırYeni kanal; temizlenemez.
channelVariantstring | nullHayırnull alanı temizler.
appModestring | nullHayırnull alanı temizler.
  • Gönderilmeyen alan değişmez. serialNumber, vendorCode, deviceModelId değiştirilemez; gövdede 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 ve 200 döner.
  • Değiştirdiğiniz alanların kaynağı (fieldSources) MANUAL olur.
  • Emekli cihaz güncellenemez: 409 physical_pos.device.retired.

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

Mağazaya ya da kasaya atama

POST /api/v1/physical-pos/devices/{deviceId}/assignment

AlanTipZorunluAçıklama
rowVersionintegerEvetCihazın son okuduğunuz rowVersion değeri.
storeIdstring (UUID)EvetHedef mağaza.
registerIdstring (UUID) | nullHayırHedef mağazanın bir kasası; yoksa cihaz mağazaya kasasız atanır.
reasonCodestringEvetCihazın açık ataması yoksa INITIAL_SETUP, CORRECTION, OTHER; varsa (taşıma) RELOCATION, REGISTER_CHANGE, DEVICE_REPLACEMENT, CORRECTION, OTHER.

Cihazın açık ataması varsa kapanır ve yenisi açılır; atama geçmişi korunur.

source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/devices/00000000-0000-0000-0000-000000000401/assignment"
BODY='{"rowVersion":1,"storeId":"00000000-0000-0000-0000-000000000102","reasonCode":"RELOCATION"}'
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"

Yanıt (200): { "device": { … }, "assignment": { … }, "previousAssignmentId": "…" }. assignment yeni atamadır (atama nesnesi); previousAssignmentId kapanan atamanın kimliği, ilk atamada null.

EngelHata
Mağaza yok404 physical_pos.store.not_found
Kasa yok ya da bu mağazanın değil404 physical_pos.register.not_found
Mağaza ya da kasa arşivli409 physical_pos.store.archived / 409 physical_pos.register.archived
Cihaz zaten aynı mağaza ve kasada409 physical_pos.device.already_assigned
Cihaz emekli409 physical_pos.device.retired

Depoya alma

POST /api/v1/physical-pos/devices/{deviceId}/assignment/close · Idempotency-Key zorunlu

Cihazın açık atamasını kapatır; cihaz mağazasız kalır (store ve register null). Cihazın terminal bağı değişmez. Cihazı silmeden mağazadan ayırmanın yoludur; ör. arşivlemek istediğiniz mağazadaki cihazlar için.

AlanTipZorunluAçıklama
rowVersionintegerEvetCihazın son okuduğunuz rowVersion değeri.
reasonCodestringEvetSTORE_CLOSED, TEMPORARILY_CLOSED, MOVED_TO_STORAGE, AWAITING_RELOCATION, CORRECTION, OTHER.

Yanıt (200): { "device": { … }, "closedAssignment": { … }, "replayed": false }. Aynı Idempotency-Key ve aynı gövdeyle tekrar replayed: true döner. Açık ataması olmayan cihaz 409 physical_pos.device.not_assigned alır.

Emekliye ayırma

POST /api/v1/physical-pos/devices/{deviceId}/retire · Idempotency-Key zorunlu

AlanTipZorunluAçıklama
rowVersionintegerEvetCihazın son okuduğunuz rowVersion değeri.
reasonCodestringEvetDEVICE_FAULT, DEVICE_LOST, DEVICE_STOLEN, END_OF_LIFE, RETURNED_TO_VENDOR, REPLACED, CREATED_IN_ERROR, DUPLICATE_RECORD, OTHER.
⚠️

Emeklilik geri alınamaz. Aynı işlemde cihazın açık ataması ve terminal bağı kapanır. Bağı kapanan terminalin rowVersion değeri artar ve terminalin değişiklik geçmişine physical_pos.audit.logical_terminal_device_unlinked olayı yazılır. Emekli cihaz güncellenemez, atanamaz ve terminale bağlanamaz.

Yanıt (200): { "device": { … }, "replayed": false }; lifecycleStatus: "RETIRED", retiredAt dolu. Cihazın etkin kimlik anahtarı ya da süresi dolmamış aktivasyon kodu varsa 409 physical_pos.device.identity_active (details.reason: active_key ya da open_activation_code).

Atama geçmişi

GET /api/v1/physical-pos/devices/{deviceId}/assignments — limit ve cursor alır, en yeni atama önce.

AlanTipAçıklama
idstring (UUID)Atamanın kimliği.
deviceIdstring (UUID)Cihaz.
storeobject | null{ id, code, name }
registerobject | null{ id, code, name }
validFromstringAtamanın başladığı zaman.
validTostring | nullAtamanın kapandığı zaman; açık atamada null.
reasonCodestringAtamayı açan işlemin gerekçesi.
createdByTypestringUSER, API_KEY, OPERATOR ya da SYSTEM.
createdByIdstringAtamayı açanın kimliği; platform tarafı işlemlerde operator.
createdAtstringKaydın oluşturulma zamanı.

Değişiklik geçmişi

GET /api/v1/physical-pos/devices/{deviceId}/audit — limit ve cursor alır; yanıt biçimi mağaza geçmişiyle aynıdır.

Cihaz olayları: physical_pos.audit.device_created, …device_updated, …device_assigned, …device_unassigned, …device_lifecycle_changed, …device_retired, …device_ownership_verified; cihaz bağı değiştiğinde …device_terminal_linked, …device_terminal_unlinked. Platform tarafı işlemlerin olaylarında actorId operator, requestId null döner.

Hatalar

HTTPcodeNe zaman
400physical_pos.idempotency.key_required / physical_pos.idempotency.key_invalidKaydetme, depoya alma ya da emeklilikte Idempotency-Key yok ya da biçim dışı.
400physical_pos.input.filter_invalidListe süzgeci geçersiz.
400physical_pos.input.serial_invalidSeri numarası üreticinin biçimine uymuyor.
400physical_pos.input.code_invalidintegrationChannel ya da appMode küme dışında.
400physical_pos.input.channel_variant_invalidchannelVariant biçim dışı.
400physical_pos.input.text_invalid / physical_pos.input.ref_invaliddisplayName ya da externalRef kurala uymuyor.
400physical_pos.input.reason_code_invalidreasonCode listede yok ya da işleme uymuyor.
400physical_pos.input.empty_patchBoş güncelleme.
400physical_pos.device.vendor_unknownÜretici katalogda yok ya da devre dışı.
400physical_pos.device.model_vendor_mismatchModel başka üreticinin.
400physical_pos.device.app_mode_invalidappMode bu kanalda kullanılamaz.
403physical_pos.environment.test_key_read_onlyYazma isteği test anahtarıyla yapıldı.
404physical_pos.device.not_foundCihaz yok, size ait değil ya da diğer ortamda.
404physical_pos.device_model.not_foundModel yok.
404physical_pos.store.not_found / physical_pos.register.not_foundHedef mağaza ya da kasa yok.
409physical_pos.device.serial_takenSeri numarası kullanımda.
409physical_pos.device.external_ref_takenexternalRef kullanımda.
409physical_pos.device.model_deprecatedModel kullanımdan kalkmış.
409physical_pos.store.archived / physical_pos.register.archivedHedef mağaza ya da kasa arşivli.
409physical_pos.device.already_assignedCihaz zaten bu mağaza ve kasada.
409physical_pos.device.not_assignedDepoya alınacak açık atama yok.
409physical_pos.device.identity_activeEtkin kimliği olan cihaz emekliye ayrılmak istendi.
409physical_pos.device.retiredEmekli cihaz değiştirilmek istendi.
409physical_pos.version_conflictrowVersion güncel değil.
409physical_pos.idempotency_mismatchAynı Idempotency-Key farklı bir istekle kullanılmış.
429RATE_LIMITEDCihaz yazma sınırı aşıldı. → Oran sınırı
503physical_pos.service.busyKayıt başka bir işlemle meşgul; aynı istekle yeniden deneyin.

Bütün kodlar: Hata Kodları.