Fiziksel POS
API Referansı
Mantıksal Terminaller

Mantıksal Terminaller

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.

Mantıksal terminal, ödeme kabul eden kimliktir: terminal kodu, POS üreticisi, üretici tarafındaki terminal kimlikleri ve bankalardaki üye işyeri ve terminal numaraları bu kayıtta durur. Fiziksel cihaz değişse de terminal ve banka bilgileri aynı kalır. → Temel kavramlar

Terminaller anahtarınızın ortamındadır: anahtar yalnız kendi ortamındaki terminalleri görür. Test anahtarı terminalleri yalnız okur; yazma istekleri 403 physical_pos.environment.test_key_read_only alır. → Ortamlar

YöntemYolKapsam
GET/api/v1/physical-pos/terminalsphysical_pos:view
POST/api/v1/physical-pos/terminalsphysical_pos:manage
GET/api/v1/physical-pos/terminals/{terminalId}physical_pos:view
PATCH/api/v1/physical-pos/terminals/{terminalId}physical_pos:manage
POST/api/v1/physical-pos/terminals/{terminalId}/closephysical_pos:manage
GET/api/v1/physical-pos/terminals/{terminalId}/auditphysical_pos:view

Banka satırları: Banka Satırları · Cihaz bağı: Cihaz Bağı. cURL örnekleri imzayı lunixi-sign.sh ile hesaplar: Kimlik Doğrulama › İmza yardımcısı.

Terminal nesnesi

AlanTipAçıklama
idstring (UUID)Terminalin kimliği.
terminalCodestringTerminal kodu; büyük harfli, ortam içinde tekil. Oluşturulduktan sonra değişmez.
displayNamestringGörünen ad.
environmentstringTEST ya da LIVE; anahtarınızın ortamı.
vendorCodestring | nullPOS üreticisinin kodu (ör. PAVO). Atanmadıysa null.
virtualSerialstring | nullÜreticinin bu terminale verdiği sanal seri numarası.
vendorTerminalRefstring | nullÜreticinin sisteminde bu terminalin kimliği.
ownershipStatusstringUNVERIFIED: terminalin size ait olduğu henüz doğrulanmadı. VERIFIED: doğrulandı.
terminalStatusstringACTIVE, SUSPENDED (geçici olarak durdurulmuş) ya da CLOSED (kapatılmış; geri alınamaz).
linkedDeviceobject | nullTerminale bağlı cihaz; bağlı cihaz yoksa null. Aşağıya bakın.
rowVersionintegerEşzamanlılık sürümü. → rowVersion
createdAtstringOluşturulma zamanı.
updatedAtstringSon değişiklik zamanı.
closedAtstring | nullKapatılma zamanı.

linkedDevice

AlanTipAçıklama
linkIdstring (UUID)Açık cihaz bağının kimliği.
deviceIdstring (UUID)Bağlı cihazın kimliği.
displayNamestring | nullCihazın görünen adı.
serialNumberstringCihazın seri numarası.
lifecycleStatusstringCihazın durumu: PENDING, ACTIVE, SUSPENDED, MAINTENANCE ya da RETIRED.
linkedAtstringBağın açıldığı zaman.

Terminalleri listeleme

GET /api/v1/physical-pos/terminals

Sorgu parametresiTipAçıklama
statusstringACTIVE, SUSPENDED ya da CLOSED. Gönderilmezse hepsi döner. Başka değer 400 physical_pos.input.filter_invalid.
qstringTerminal kodunun ya da görünen adı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.
source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/terminals?status=ACTIVE&q=IST"
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-000000000301",
        "terminalCode": "IST-KADIKOY-01",
        "displayName": "Kadıköy Kasa 1",
        "environment": "LIVE",
        "vendorCode": "PAVO",
        "virtualSerial": null,
        "vendorTerminalRef": "PV-000123",
        "ownershipStatus": "UNVERIFIED",
        "terminalStatus": "ACTIVE",
        "linkedDevice": null,
        "rowVersion": 2,
        "createdAt": "2026-01-01T07:20:00.000Z",
        "updatedAt": "2026-01-02T08:00:00.000Z",
        "closedAt": null
      }
    ],
    "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null }
  },
  "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null },
  "statusCode": 200,
  "requestId": "00000000-0000-0000-0000-000000000000"
}

Terminal oluşturma

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

AlanTipZorunluAçıklama
codestringEvetTerminal kodu: A-Z, 0-9, ., _, -; en çok 64 karakter. Büyük harfe çevrilir. Ortam içinde tekildir; kapatılmış terminaller de kodlarını korur.
displayNamestringEvetGörünen ad, en çok 120 karakter. Metin kurallarına tabidir.
vendorCodestringKoşulluKatalogdaki etkin bir üreticinin kodu. virtualSerial ya da vendorTerminalRef gönderiyorsanız zorunludur. → Katalog › Üreticiler
virtualSerialstringHayırÜreticinin verdiği sanal seri: A-Z, 0-9; en çok 64 karakter. Büyük harfe çevrilir.
vendorTerminalRefstringHayırÜreticinin sistemindeki terminal kimliği: A-Z, a-z, 0-9, ., _, -; en çok 128 karakter. Büyük/küçük harf korunur.

Gövdede environment gönderilmez; terminal anahtarınızın ortamında açılır. Yeni terminal terminalStatus: "ACTIVE" ve ownershipStatus: "UNVERIFIED" ile başlar.

source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/terminals"
BODY='{"code":"ist-kadikoy-01","displayName":"Kadıköy Kasa 1","vendorCode":"PAVO","vendorTerminalRef":"PV-000123"}'
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-000000000003" \
  --data-raw "$BODY"
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "terminal": {
      "id": "00000000-0000-0000-0000-000000000301",
      "terminalCode": "IST-KADIKOY-01",
      "displayName": "Kadıköy Kasa 1",
      "environment": "LIVE",
      "vendorCode": "PAVO",
      "virtualSerial": null,
      "vendorTerminalRef": "PV-000123",
      "ownershipStatus": "UNVERIFIED",
      "terminalStatus": "ACTIVE",
      "linkedDevice": null,
      "rowVersion": 1,
      "createdAt": "2026-01-01T07:20:00.000Z",
      "updatedAt": "2026-01-01T07:20:00.000Z",
      "closedAt": null
    },
    "replayed": false
  },
  "statusCode": 201,
  "requestId": "00000000-0000-0000-0000-000000000000"
}
EngelHata
Aynı ortamda aynı kodla bir terminal var409 physical_pos.terminal.code_taken
Aynı üretici ve vendorTerminalRef ile kapatılmamış bir terminaliniz var409 physical_pos.terminal.vendor_ref_taken
Aynı virtualSerial ile kapatılmamış bir terminaliniz var409 physical_pos.terminal.virtual_serial_taken
virtualSerial ya da vendorTerminalRef var, vendorCode yok400 physical_pos.terminal.vendor_required
Üretici katalogda yok ya da devre dışı400 physical_pos.device.vendor_unknown

vendorTerminalRef ve virtualSerial tekilliği ortamdan bağımsızdır: aynı değeri bir test ve bir canlı terminalde aynı anda kullanamazsınız. Terminal kapatıldığında bu değerler serbest kalır.

Terminal ayrıntısı

GET /api/v1/physical-pos/terminals/{terminalId}

Terminal nesnesine ek olarak doğrulama bilgisi ve banka satırlarının ilk sayfası (en çok 100 satır) döner:

{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "terminal": {
      "id": "00000000-0000-0000-0000-000000000301",
      "terminalCode": "IST-KADIKOY-01",
      "displayName": "Kadıköy Kasa 1",
      "environment": "LIVE",
      "vendorCode": "PAVO",
      "virtualSerial": null,
      "vendorTerminalRef": "PV-000123",
      "ownershipStatus": "UNVERIFIED",
      "terminalStatus": "ACTIVE",
      "linkedDevice": null,
      "rowVersion": 1,
      "createdAt": "2026-01-01T07:20:00.000Z",
      "updatedAt": "2026-01-01T07:20:00.000Z",
      "closedAt": null,
      "verifiedAt": null,
      "verifiedVia": null
    },
    "acquirers": {
      "items": [],
      "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null }
    }
  },
  "statusCode": 200,
  "requestId": "00000000-0000-0000-0000-000000000000"
}
AlanAçıklama
terminal.verifiedAtSahipliğin doğrulandığı zaman; doğrulanmadıysa null.
terminal.verifiedViaDoğrulamanın kaynağı: DEVICE, VENDOR_ACCOUNT ya da OPERATOR; doğrulanmadıysa null.
acquirersBanka satırlarının ilk sayfası. acquirers.pageInfo.hasMore true ise kalan satırları banka satırı listesinden cursor ile okuyun.

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

Terminal güncelleme ve üretici atama

PATCH /api/v1/physical-pos/terminals/{terminalId}

AlanTipZorunluAçıklama
rowVersionintegerEvetSon okuduğunuz rowVersion.
displayNamestringHayırYeni görünen ad, en çok 120 karakter.
vendorCodestringHayırÜreticisiz oluşturulmuş terminale üretici atar. Aşağıya bakın.

displayName ya da vendorCode alanlarından en az biri gönderilmelidir; ikisi de yoksa 400 physical_pos.input.empty_patch. Gönderilen değerler mevcut değerlerle aynıysa kayıt değişmez, rowVersion artmaz, değişiklik geçmişine olay yazılmaz ve 200 döner.

Üretici bir kez atanır. Üreticisi olmayan bir terminale vendorCode ile üretici atayabilirsiniz; atandıktan sonra değişmez:

  • Terminalin henüz banka satırı olmamalıdır.
  • Terminale bağlı bir cihaz varsa, atanan üretici cihazın üreticisiyle aynı olmalıdır; değilse 400 physical_pos.terminal.device_vendor_mismatch.
  • Üreticisi zaten olan terminale aynı kodu göndermek değişiklik sayılmaz. Farklı kod 409 physical_pos.record.field_immutable alır.
  • Banka satırı olan üreticisiz terminale atama da 409 physical_pos.record.field_immutable alır.
source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/terminals/00000000-0000-0000-0000-000000000301"
BODY='{"rowVersion":1,"displayName":"Kadıköy Ana Kasa"}'
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: { "terminal": { … } }. Kapatılmış terminal güncellenemez: 409 physical_pos.terminal.closed.

Terminali kapatma

POST /api/v1/physical-pos/terminals/{terminalId}/close

AlanTipZorunluAçıklama
rowVersionintegerEvetSon okuduğunuz rowVersion.
reasonCodestringEvetMERCHANT_REQUEST, CONTRACT_ENDED, BANK_TERMINATED, CREATED_IN_ERROR, DUPLICATE_RECORD, MIGRATED, OTHER. → Gerekçe kodları
⚠️

Kapatma geri alınamaz. Aynı işlemde terminalin etkin banka satırları DISABLED olur; terminalin bağlı cihazı varsa bağ kapanır. Kapatılmış terminal güncellenemez, banka satırı eklenemez ve cihaz bağlanamaz; kodu kullanımda kalır.

source lunixi-sign.sh
REQ_PATH="/api/v1/physical-pos/terminals/00000000-0000-0000-0000-000000000301/close"
BODY='{"rowVersion":4,"reasonCode":"CONTRACT_ENDED"}'
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: { "terminal": { … } }, terminalStatus: "CLOSED", closedAt dolu, linkedDevice: null. Terminal zaten kapalıysa 409 physical_pos.terminal.closed.

Değişiklik geçmişi

GET /api/v1/physical-pos/terminals/{terminalId}/audit — limit ve cursor alır. Terminalin kendi olaylarını ve banka satırlarının olaylarını birlikte döner:

{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "items": [
      {
        "id": "00000000-0000-0000-0000-000000000902",
        "action": "physical_pos.audit.terminal_acquirer_added",
        "entityType": "terminal_acquirer",
        "entityId": "00000000-0000-0000-0000-000000000601",
        "actorType": "API_KEY",
        "actorId": "kid:mk_live_00000000",
        "reasonCode": null,
        "changes": {
          "logicalTerminalId": "00000000-0000-0000-0000-000000000301",
          "vendorAcquirerRef": "B01",
          "acquirerNo": "0000",
          "mappingStatus": "MAPPED",
          "merchantNumber": "000000000000001",
          "terminalNumber": "PS000001",
          "currencyCount": 1,
          "labelChanged": true,
          "source": "MANUAL",
          "verificationStatus": "UNVERIFIED",
          "toStatus": "ACTIVE"
        },
        "environment": "LIVE",
        "createdAt": "2026-01-01T07: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"
}
entityTypeOlaylar (action)
logical_terminalphysical_pos.audit.logical_terminal_created, …logical_terminal_updated, …logical_terminal_closed, …logical_terminal_device_changed, …logical_terminal_device_unlinked
terminal_acquirerphysical_pos.audit.terminal_acquirer_added, …terminal_acquirer_updated, …terminal_acquirer_disabled (terminal kapatılırken)

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_invaliddisplayName kurala uymuyor.
400physical_pos.input.filter_invalidListe süzgeci (status, q) geçersiz.
400physical_pos.input.vendor_code_invalidvendorCode biçim dışı.
400physical_pos.input.virtual_serial_invalidvirtualSerial biçim dışı.
400physical_pos.input.ref_invalidvendorTerminalRef biçim dışı.
400physical_pos.input.reason_code_invalidreasonCode listede yok.
400physical_pos.device.vendor_unknownÜretici katalogda yok ya da devre dışı.
400physical_pos.terminal.vendor_requiredÜretici kimliği verildi ama vendorCode yok.
400physical_pos.terminal.device_vendor_mismatchAtanan üretici bağlı cihazın üreticisinden farklı.
400physical_pos.input.empty_patchBoş güncelleme.
400physical_pos.cursor.invalidBozuk imleç.
403physical_pos.environment.test_key_read_onlyYazma isteği test anahtarıyla yapıldı.
404physical_pos.terminal.not_foundTerminal yok, size ait değil ya da diğer ortamda.
409physical_pos.terminal.code_takenKod bu ortamda kullanımda.
409physical_pos.terminal.vendor_ref_takenvendorTerminalRef açık bir terminalde kullanımda.
409physical_pos.terminal.virtual_serial_takenvirtualSerial açık bir terminalde kullanımda.
409physical_pos.terminal.closedKapatılmış terminal değiştirilmek istendi.
409physical_pos.record.field_immutableÜretici zaten atanmış ya da terminalin banka satırı var.
409physical_pos.version_conflictrowVersion güncel değil.
409physical_pos.idempotency_mismatchAynı Idempotency-Key farklı bir istekle kullanılmış.
429RATE_LIMITEDTerminal ailesi yazma sınırı aşıldı. → Oran sınırı

Bütün kodlar: Hata Kodları.