Uç noktalar
Tüm adresler https://app.mekante.com/api/v1/public ile başlar. Her istekte Authorization: Bearer sk_live_… başlığı gerekir (Kimlik doğrulama). Örneklerdeki kimlikler (id) kısaltılmıştır.
| Yöntem | Yol | Ne yapar |
|---|---|---|
GET | /me | Anahtarın bağlı olduğu işletme, program ve şube |
POST | /scan | Müşterinin QR kodunu okutur |
GET | /scans/:id | Kullanılabilir bir okutmayı yeniden okur |
POST | /earn/preview | Yazılacak puanı hesaplar, kaydetmez |
POST | /earn | Puan yazar |
POST | /redeem | Ödül düşer |
POST | /ledger/:id/void | Bir girişi geri alır |
GET | /ledger/recent | Son 20 işlem |
GET | /ledger/mine | Anahtarın kendi işlemleri, sayfa sayfa |
GET /me
Anahtarın bağlı olduğu işletmeyi, sadakat programını ve şubeleri döner. Anahtarının çalıştığını denemek için de kullanışlıdır.
curl https://app.mekante.com/api/v1/public/me \
-H "Authorization: Bearer sk_live_ORNEK_ANAHTAR"
200 yanıtında role, tenant, program ve locations alanları bulunur. program.type points ya da stamps olur.
POST /scan
Müşterinin QR kodunu okutur ve bir scanId üretir.
Gövde
| Alan | Tür | Açıklama |
|---|---|---|
token | metin, 10–1000 karakter | QR kodun içeriği |
locationId | uuid, isteğe bağlı | Şube. Anahtar tek şubeye bağlı olduğu için gerekmez |
curl -X POST https://app.mekante.com/api/v1/public/scan \
-H "Authorization: Bearer sk_live_ORNEK_ANAHTAR" \
-H "Content-Type: application/json" \
-d '{ "token": "QR_KODUN_ICERIGI" }'
Yanıt 200
{
"scanId": "e227e15a-…",
"intent": "earn",
"member": {
"id": "db997e9d-…",
"name": "Ayşe Yılmaz",
"phone": "+90 559 *** ** 39",
"balance": 0,
"stampBalance": 0,
"tier": null
},
"program": { "type": "points", "stampsPerReward": null, "maxStampsPerTransaction": 10 },
"reward": null
}
intent earn (puan ya da damga yazma) ya da redeem (ödül düşme) olur. redeem ise reward alanı { id, name, costPoints, costCurrency } içerir; costPoints ödülün bedelidir, costCurrency bedelin points (puan) ya da stamps (damga) olarak ödendiğini söyler. Telefon numarası her zaman maskelenir.
program.type işletmenin programını gösterir:
| Tür | Ne yazılır |
|---|---|
points | Satış tutarından puan. amount zorunludur |
stamps | Damga. Tutar sorulmaz; stamps ile kaç damga verileceğini yaz (varsayılan 1) |
hybrid | İki ayrı bakiye. stamps kadar damga yazılır; amount da verirsen o tutardan puan da yazılır |
rewards yalnızca müşterinin normal QR kodunda gelir (müşteri bir ödül seçtiyse boştur ve reward doludur). Her ödül { id, name, type, costPoints, costCurrency, eligible, reason, missing } içerir: eligible ödülün şimdi kullanılıp kullanılamayacağı, reason kullanılamıyorsa nedeni (INSUFFICIENT_BALANCE, OUT_OF_STOCK, LIMIT_REACHED, EXPIRED, NOT_STARTED, INACTIVE) ve missing yetmeyen puan ya da damga sayısıdır. Liste en ucuz ödülden başlar.
member.balance puan bakiyesi, member.stampBalance damga bakiyesidir. program.maxStampsPerTransaction tek ziyarette verilebilecek en çok damgadır.
Olası hatalar: 400 QR_INVALID, 400 QR_EXPIRED, 409 QR_ALREADY_USED, 404 MEMBERSHIP_NOT_FOUND, 402 TRIAL_EXPIRED, 402 SUBSCRIPTION_SUSPENDED.
GET /scans/:id
Henüz kullanılmamış ve süresi dolmamış bir okutmayı, POST /scan ile aynı gövdeyle döner. Ekran yenilense bile tutar giriş ekranına dönebilmek için kullan. Kullanılmış ya da süresi dolmuşsa 409 SCAN_INVALID.
POST /earn/preview
Bir ziyaretin kaç puan ve damga yazacağını hesaplar. Hiçbir şey kaydetmez ve Idempotency-Key gerektirmez.
Gövde: scanId (uuid); amount (kuruş, pozitif tam sayı; points programında zorunlu, hybrid programında isteğe bağlı, stamps programında yok sayılır); stamps (tam sayı; stamps ve hybrid programlarında, varsayılan 1).
{ "scanId": "e227e15a-…", "amount": 15000 }
Yanıt 200
{
"points": 150,
"stamps": 0,
"multiplier": 1,
"multiplierCampaignId": null,
"bonuses": [],
"total": 150,
"stampsTotal": 0,
"expiresAt": "2027-10-23T09:57:08.237Z",
"balanceAfter": 150,
"stampBalanceAfter": 0
}
multiplier seviye ya da kampanya çarpanıdır (çarpanlar birikmez, en yükseği uygulanır); yalnızca puanlara uygulanır. total bu ziyarette yazılacak toplam puandır, stampsTotal toplam damgadır (bonuslar dahil: damga programında hoş geldin ve doğum günü bonusları damga olarak, diğerlerinde puan olarak yazılır). expiresAt bu puan ve damgaların son kullanma tarihidir.
POST /earn
Puan ve/veya damga yazar. Idempotency-Key başlığı zorunludur (Kasa akışı).
Gövde
| Alan | Tür | Açıklama |
|---|---|---|
scanId | uuid | POST /scan yanıtından |
amount | tam sayı, kuruş | Satış tutarı. points programında zorunlu, hybrid programında isteğe bağlı (verilirse puan yazılır), stamps programında yok sayılır |
stamps | tam sayı, isteğe bağlı | Verilecek damga sayısı (stamps ve hybrid programları, varsayılan 1, işletmenin üst sınırına kadar). Hibritte 0 yazıp yalnızca puan verebilirsin |
receiptNo | metin, 1–40, isteğe bağlı | Fiş numarası. Aynı numara ikinci kez yazılamaz |
curl -X POST https://app.mekante.com/api/v1/public/earn \
-H "Authorization: Bearer sk_live_ORNEK_ANAHTAR" \
-H "Idempotency-Key: pos-2026-000123" \
-H "Content-Type: application/json" \
-d '{ "scanId": "e227e15a-…", "amount": 15000, "receiptNo": "A-1042" }'
Yanıt 201 (tekrar gönderimde 200 ve "replayed": true)
{
"replayed": false,
"entries": [{ "id": "3f99048a-…", "type": "earn", "points": 150, "stamps": 0 }],
"total": 150,
"stamps": 0,
"balance": 150,
"stampBalance": 0,
"membershipId": "db997e9d-…"
}
entries[].id geri alma için kullanacağın kayıt kimliğidir. total ve stamps bu işlemde yazılan puan ve damgadır, balance ve stampBalance işlemden sonraki bakiyelerdir. Damga programında total 0 olur; damga sayısını stamps alanından oku.
Olası hatalar: 400 (başlık ya da gövde eksik), 409 SCAN_INVALID, 404 SCAN_NOT_FOUND, 409 DUPLICATE_RECEIPT, 409 DUPLICATE_REQUEST, 422 AMOUNT_TOO_HIGH, 429 DAILY_EARN_LIMIT, 429 CASHIER_DAILY_LIMIT, 400 INVALID_AMOUNT, 400 INVALID_STAMPS, 422 TOO_MANY_STAMPS, 400 NOTHING_TO_EARN (hibritte ne damga ne tutar var).
POST /redeem
Ödül düşer. Idempotency-Key zorunludur.
Gövde: scanId (uuid) ve rewardId (uuid, isteğe bağlı). Müşterinin normal QR kodunu okuttuysan kasiyerin seçtiği rewardId zorunludur (400 REWARD_REQUIRED). Müşteri bir ödül için QR üretmişse ödül QR'dadır; rewardId gönderirsen aynı olmalıdır (400 REWARD_MISMATCH).
Yanıt 201
{
"replayed": false,
"entries": [{ "id": "922b40fd-…", "type": "redeem", "points": -100, "stamps": 0 }],
"total": -100,
"stamps": 0,
"balance": 250,
"stampBalance": 3,
"membershipId": "db997e9d-…",
"code": "WZ86BV",
"reward": {
"id": "7d5cb889-…",
"name": "Bedava kahve",
"costPoints": 100,
"costCurrency": "points"
}
}
code müşteriye gösterilecek ya da kasa ekranında doğrulanacak 6 karakterlik ödül kodudur.
Olası hatalar: 400 REWARD_REQUIRED, 400 REWARD_MISMATCH, 429 CASHIER_DAILY_LIMIT, 409 INSUFFICIENT_BALANCE, 409 REWARD_OUT_OF_STOCK, 409 REWARD_INACTIVE, 409 REWARD_EXPIRED, 409 REWARD_NOT_STARTED, 409 REWARD_LIMIT_REACHED, 404 REWARD_NOT_FOUND, 409 SCAN_INVALID, 409 DUPLICATE_REQUEST.
POST /ledger/:id/void
:id bir earn ya da redeem kaydının kimliğidir (entries[].id). Gövde gerekmez.
curl -X POST https://app.mekante.com/api/v1/public/ledger/922b40fd-…/void \
-H "Authorization: Bearer sk_live_ORNEK_ANAHTAR"
Yanıt 200: kayıt bir reverse girişiyle geri alınır.
{
"replayed": false,
"entries": [{ "id": "fab26888-…", "type": "reverse", "points": 100, "stamps": 0 }],
"total": 100,
"stamps": 0,
"balance": 350,
"stampBalance": 3,
"membershipId": "db997e9d-…"
}
Olası hatalar: 404 ENTRY_NOT_FOUND, 409 ALREADY_VOIDED, 409 POINTS_ALREADY_SPENT, 409 NOT_VOIDABLE, 403 FORBIDDEN (başkasının girişi), 403 VOID_WINDOW_PASSED (15 dakika geçti).
GET /ledger/recent
Anahtarın yaptığı son 20 puan kazanımı ve ödül kullanımını, en yeniden eskiye doğru, bir dizi olarak döner.
[
{
"id": "3f99048a-…",
"type": "earn",
"points": 150,
"amount": 15000,
"createdAt": "2026-10-23T09:57:08.246Z",
"voided": false,
"member": "Ayşe Yılmaz"
}
]
GET /ledger/mine
Anahtarın kendi yaptığı işlemleri sayfa sayfa döner.
Sorgu: limit (1–100, varsayılan 50), cursor (önceki yanıttaki nextCursor).
{
"items": [
{
"id": "3f99048a-…",
"type": "earn",
"points": 150,
"amount": 15000,
"createdAt": "2026-10-23T09:57:08.246Z",
"voided": false,
"member": "Ayşe Yılmaz"
}
],
"nextCursor": null
}
nextCursor boş (null) olduğunda son sayfadasın.