Kurumsal Hesaplar & Çalışan Yönetimi
- Taban yol
/api/v1/wallet- Kimlik
- Ed25519 istek imzası —
X-Key-Id,X-Date,X-Nonce,Digest(body varsa),X-Signature. Zaman penceresi ±5 dk, nonce tek kullanımlık, anahtarda IP allow-list olabilir. - Yetki
- Anahtarınız cüzdan ürününü ve çağrının gerektirdiği cüzdan iznini taşımalıdır; izni olmayan çağrı
403 WALLET_INSUFFICIENT_SCOPEalır. Uç başına izinler: Anahtar izinleri. - Çapraz yüzey
- Bu uçlar s2s yüzeyindedir. Panelde ayrıca
GET corporate-accounts/:idvePATCH corporate-accounts/:idvardır (wallet:enduser:read/wallet:enduser:manage); bunların s2s karşılığı YOKTUR.
Bir kurumsal hesap, bir işverenin çalışanlarını tek bir çatı altında toplar. Yemek kartı, ulaşım ödeneği, harcırah ve benzeri kurumsal cüzdan senaryolarının taşıyıcısıdır.
Bu işlemleri KİM yapar? Bugün program operatörü — yani cüzdan programını işleten kurum — panelden ya da s2s API'den yapar. İşverenin kendi girip çalışanlarını yönetebileceği bir self-servis yüzey YOKTUR. Bir işveren kendi kadrosunu yönetmek isterse, program operatörünün onun adına işlem yapması gerekir.
Kurumsal hesap bir giriş kimliği değildir: kullanıcı adı, parola veya oturum taşımaz. Müşteri portalı son kullanıcıya (cüzdan sahibine) aittir; işverene ait bir portal bulunmuyor.
Kurumsal hesabın kendisi para tutmaz. Para her zaman çalışanın kendi cüzdanındadır; kurumsal hesap yalnız aidiyet ve yetki taşır. Bu ayrım, aşağıdaki "ayırma paraya dokunmaz" davranışının tek sebebidir.
Yeni bir izin ailesi (wallet:corporate:*) icat edilmedi: kurumsal hesap yönetimi son kullanıcı yönetiminin bir parçasıdır ve aynı izin kodlarını kullanır.
s2s yüzeyinde kurumsal hesabın dört ucu da anahtarınızda wallet:bulk:create iznini gerektirir. Bkz. Anahtar izinleri.
Uçlar
Panel yüzeyi (Bearer JWT + RBAC):
POST corporate-accounts # yeni kurumsal hesap
GET corporate-accounts # programId, status, limit, cursor
GET corporate-accounts/:id # detay
PATCH corporate-accounts/:id # name / status
POST corporate-accounts/:id/employees/import # toplu çalışan ekleme
POST corporate-accounts/:id/employees/offboard # toplu çalışan ayırmaSunucudan sunucuya (s2s, imzalı):
POST /api/v1/wallet/corporate-accounts
GET /api/v1/wallet/corporate-accounts
POST /api/v1/wallet/corporate-accounts/:id/employees/import
POST /api/v1/wallet/corporate-accounts/:id/employees/offboards2s yüzeyinde detay (GET :id) ve güncelleme (PATCH :id) uçları yoktur — bu ikisi yalnız panelde bulunur. Entegrasyonunuzu kurumsal hesabı s2s'ten okuyacak şekilde kurmayın; liste ucunu (GET corporate-accounts) kullanın.
s2s'teki üç mutasyon ucu (POST corporate-accounts, employees/import, employees/offboard) Idempotency-Key başlığı zorunludur. Bkz. Kimlik Doğrulama.
Kurumsal hesap tanımı
| Alan | Zorunlu | Açıklama |
|---|---|---|
programId | ✅ | Hangi cüzdan programına ait — değiştirilemez |
code | ✅ | İşveren kodu (1–64). Kaydedilirken kırpılır ve büyük harfe çevrilir; program içinde tekildir — değiştirilemez |
name | ✅ | Görünen ad (1–160) |
status | — | ACTIVE | ARCHIVED (varsayılan ACTIVE) |
PATCH corporate-accounts/:id yalnız name ve status alanlarını kabul eder.
code büyük harfe normalize edilir: acme ile ACME aynı koddur ve ikincisi tekillik hatası alır. Kendi tarafınızda kodu üretirken bunu varsayın; aksi hâlde "kaydettim ama listede yok" gibi görünen bir çakışma yaşarsınız.
Çalışan bağı
Bir son kullanıcının en fazla bir işvereni olabilir (corporateAccountId).
- Tek kullanıcı oluştururken:
POST end-usersgövdesindekicorporateAccountId. - Toplu:
employees/import. - Kadro listesi:
GET end-users?corporateAccountId=<id>.
Zaten başka bir kuruma bağlı bir kullanıcıyı içe aktarmaya çalışmak WALLET_CORPORATE_LINK_CONFLICT ile reddedilir — bağ sessizce yeni kuruma taşınmaz. Çalışan iş değiştirdiyse önce eski işverenden ayırın, sonra yenisine aktarın.
Toplu içe aktarma
POST corporate-accounts/:id/employees/importGövde, satır dizisidir (rows, 1–1000 satır):
| Satır alanı | Zorunlu | Kural |
|---|---|---|
phone | ✅ | E.164 benzeri numara, 8–20 karakter (+, rakam, boşluk, parantez, tire) |
displayName | — | En çok 120 karakter |
externalCustomerId | — | En çok 128 karakter — kendi sisteminizdeki kimlik |
kycRef | — | En çok 128 karakter |
CSV tarayıcıda ayrıştırılır. Uç, CSV metni değil bir JSON satır dizisi kabul eder; yukarıdaki dört alan CSV kolonlarınızın karşılığıdır. accountType alanı yoktur ve gönderilirse istek reddedilir: içe aktarma her zaman bireysel (PERSONAL) hesap açar.
Hepsi-ya-da-hiçbiri
İçe aktarma atomiktir. Tek bir satır bile hata verirse hiçbir satır yazılmaz — o ana kadar oluşturulmuş kullanıcılar, cüzdanlar ve hesaplar dâhil her şey geri alınır.
Yanıt bu durumda HTTP 422 ve code: WALLET_BULK_IMPORT_REJECTED olur; rapor details altında döner ve hatasız satırların durumu ROLLED_BACK olarak işaretlenir. "Bir kısmı geçti" diye bir durum yoktur — dosyayı düzeltip tamamını yeniden yükleyin.
Satır durumları
| Durum | Anlamı |
|---|---|
CREATED | Numara sistemde yoktu — kullanıcı ve varsayılan cüzdanı oluşturuldu, kuruma bağlandı |
LINKED_EXISTING | Kullanıcı vardı ve hiçbir kuruma bağlı değildi — bu kuruma bağlandı |
ALREADY_LINKED | Kullanıcı zaten bu kuruma bağlıydı — hiçbir yazma yapılmadı |
ERROR | Satır reddedildi (aşağıdaki kodlar) |
ROLLED_BACK | Satır geçerliydi ama yazılmadı, çünkü başka bir satır hata verdi |
Satır hata kodları: WALLET_CORPORATE_LINK_CONFLICT (başka kuruma bağlı), WALLET_ENDUSER_CLOSED (kullanıcı kapalı), WALLET_VALIDATION (biçim), WALLET_ENDUSER_EXISTS (dosya içinde tekrarlanan kayıt).
Başarılı yanıt
{
"status": "success",
"code": "SUCCESS",
"data": {
"applied": true,
"corporateAccountId": "…",
"totalRows": 120,
"createdCount": 94,
"linkedCount": 21,
"alreadyLinkedCount": 5,
"errorCount": 0,
"results": [
{ "index": 0, "phoneMasked": "+90 5** *** ** 41", "status": "CREATED", "endUserId": "…" }
]
}
}Yanıt ham telefon numarası taşımaz, yalnız phoneMasked. Satırı kendi dosyanızla eşlemek için index veya externalCustomerId alanını kullanın.
totalRows her zaman gönderdiğiniz satır sayısıdır; reddedilen bir yüklemede results yalnız hatalı satırları taşıyabilir, dolayısıyla results.length ile totalRows eşit olmayabilir.
İçe aktarma, kurumsal hesap ve program ACTIVE değilse reddedilir.
Çalışan ayırma (offboard)
POST corporate-accounts/:id/employees/offboard| Gövde alanı | Zorunlu | Kural |
|---|---|---|
rows[] | ✅ | 1–1000 satır |
rows[].endUserId | ◑ | UUID — externalCustomerId ile tam olarak biri verilir |
rows[].externalCustomerId | ◑ | En çok 128 karakter |
reason | — | En çok 240 karakter — yalnız denetim kaydı, karara etkisi yok |
Satır durumları: OFFBOARDED · ALREADY_OFFBOARDED · ERROR · ROLLED_BACK.
Satır hata kodları: WALLET_CORPORATE_NOT_MEMBER, WALLET_NOT_FOUND, WALLET_VALIDATION, WALLET_ENDUSER_EXISTS.
Ayırma da hepsi-ya-da-hiçbiridir; reddedilen bir çağrı HTTP 422 ve code: WALLET_BULK_OFFBOARD_REJECTED döner.
Ayırma paraya DOKUNMAZ
Ayırma bir para işlemi değildir. Çalışanın bakiyesi kendisinde kalır ve çalışan harcamaya devam eder. Kesilen tek şey, kurumun o çalışan üzerindeki yetkisidir.
Somut olarak ayırma yalnız kurumsal bağ alanlarını günceller. Ayırmadan sonra:
- Kullanıcının durumu
ACTIVEkalır — dondurulmaz. - Cüzdanları ve hesapları
ACTIVEkalır. - Ledger'a hiçbir kayıt yazılmaz, bakiye okunmaz bile.
- Kartlar dondurulmaz.
Bu bilinçli bir karardır: elektronik para hamilinin geri ödeme hakkı koşulsuzdur, dolayısıyla bir işveren ilişkisinin sona ermesi hamilin parasına el konulmasının gerekçesi olamaz. Bakiyeyi geri alan, süpüren veya kuruma aktaran bir uç yoktur ve eklenmemelidir.
Ürün metinlerinizde ve panel ekranınızda ayırmayı "bakiye geri alınır" izlenimi verecek şekilde anlatmayın. Doğru cümle: "Çalışan kurum kadrosundan çıkarılır; mevcut bakiyesi kendisinde kalır."
Kurumun yüklediği paranın geri alınmasını gerektiren bir ticari düzeniniz varsa bunu yükleme tarafında çözün (ör. dönemsel yükleme), ayırma ucunda değil.
Ayırma, içe aktarmadan farklı olarak kurumsal hesabın veya programın ACTIVE olmasını gerektirmez. Bir yetkinin geri alınması, o yetkiyi veren kabın durumu yüzünden engellenmemelidir — arşivlenmiş bir işveren de kadrosunu serbest bırakabilir.
Aynı çalışanı ikinci kez ayırmak hata değildir: ALREADY_OFFBOARDED döner.
Kurumsal harcama kısıtı
Bir kurumun çalışanlarına özel harcama kuralları (hangi kategoride, hangi kanalda, hangi saatlerde harcanabilir) ayrı bir motorla tanımlanır: Harcama Kısıtı.
Kontrol listesi
-
codeüretiminiz büyük harf normalizasyonunu varsayıyor - İçe aktarma yanıtındaki
appliedalanı kontrol ediliyor; 422 gövdesindekidetails.resultsoperatöre gösteriliyor -
ROLLED_BACKsatırlar kullanıcıya "başarısız" değil "yazılmadı" olarak anlatılıyor - Ayırma ekranında bakiyeye dair yanıltıcı ifade yok
- İş değiştiren çalışan için önce ayırma, sonra içe aktarma sırası uygulanıyor
- s2s mutasyonlarında
Idempotency-Keygönderiliyor