Yenileme ve İptal

1.6k görüntülenme Markdown

Dönem sonunu yürüten on uç: yenileme faturası, iptal talepleri, iade ve abonelik iptali.

Genel Bakış

Bir dönem bittiğinde iki yol vardır: yenilenir ya da biter. Bu on uç ikisini de yürütür — yenileme faturasını üretir, müşterinin iptal talebini karara bağlar, hizmeti iade ile birlikte kapatır ve ödeme aboneliğini durdurur.

Dört ayrı şey birbirine karışmaya çok müsait: yenileme faturası parayı ister, iptal talebi müşterinin isteğidir, iptal ve iade hizmeti kapatıp parayı geri verir, abonelik iptali yalnız otomatik tahsilatı durdurur. Hiçbiri diğerini kendiliğinden yapmaz.

Referans

Hizmet Yenileme Faturası

post/api/v1/admin/services/{id}/renewal-invoice
Services/GenerateServiceRenewalInvoice admin 201

Hizmet için yenileme faturası üretir. Cron'un kullandığı yolun aynısını elle çalıştırır.

Gövde —
——Gövde gerekmez, boş gönderin. Yenileme ayarları — kaynak, ek hizmet toplama, metrik, bildirim ve kanca — sunucu tarafında sabit; buradan verilemez.
Dönen alanlar data — 2
invoice_idintÜretilen faturanın kimliği.
service_idintHizmet kimliği.
Hatalar 3
not_found404Hizmet bulunamadı.
renewal_skipped422Fatura üretilmedi. Dönem zaten faturalanmış, hizmette yenileme faturası kapatılmış, dönem geçersiz ya da müşteri verisi eksik olabilir; mesaj hangisi olduğunu söyler.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -X POST 'https://panel.ornek.com/api/v1/admin/services/529/renewal-invoice' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.ornek.com/api/v1/admin/services/529/renewal-invoice', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/services/529/renewal-invoice');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Atlama bir HATA degil bir KARARDIR; sebebi mesajda yazar.
$response = Api::Services()->GenerateServiceRenewalInvoice(['id' => 529]);

if (($response['error']['code'] ?? '') === 'renewal_skipped') {
    $why = $response['error']['message'];
}
Yanıt
{
  "data": {
    "invoice_id": 1234,
    "service_id": 529
  }
}
{
  "error": {
    "code": "renewal_skipped",
    "message": "Renewal skipped: this period is already invoiced."
  }
}

Ek Hizmet Yenileme Faturası

post/api/v1/admin/services/{id}/addons/{addon_id}/renewal-invoice
Services/GenerateAddonRenewalInvoice admin 201

Tek bir ek hizmet için yenileme faturası üretir.

Gövde —
——Gövde gerekmez, boş gönderin.
Dönen alanlar data — 2
invoice_idintÜretilen faturanın kimliği.
addon_idintEk hizmet kaydının kimliği.
Hatalar 3
not_found404Hizmet ya da ek hizmet bulunamadı.
renewal_skipped422Fatura üretilmedi.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -X POST 'https://panel.ornek.com/api/v1/admin/services/529/addons/44/renewal-invoice' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.ornek.com/api/v1/admin/services/529/addons/44/renewal-invoice', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/services/529/addons/44/renewal-invoice');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Hizmet yenilemesi ek hizmetleri zaten toplar; bu uc yalniz TEK BASINA yenileme icindir.
$response = Api::Services()->GenerateAddonRenewalInvoice([
    'id'       => 529,
    'addon_id' => 44,
]);

İptal ve İade

post/api/v1/admin/services/{id}/cancel-refund
Services/CancelAndRefundService admin geri alınamaz

Hizmeti iptal eder ve isterseniz kullanılmamış dönemi iade eder.

Gövde 2
refundstringİade biçimi: none iade yok, credit müşteri bakiyesine, cash gider kaydı olarak. Varsayılan none.
apply_on_moduleboolSağlayıcıdaki hesabı da iptal eder.
Dönen alanlar data — 5
statusstringİşlem sonrası durum.
idintHizmet kimliği.
refundstringİstediğiniz iade biçimi.
refundedboolİadenin gerçekten yapılıp yapılmadığı. İstemekle olmaz: kalan bakiye yoksa yanlış döner.
applied_on_moduleboolSağlayıcıya uygulandı mı.
Hatalar 3
not_found404Hizmet bulunamadı.
already_cancelled422Hizmet zaten iptal edilmiş.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -X POST 'https://panel.ornek.com/api/v1/admin/services/529/cancel-refund' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"refund":"credit","apply_on_module":true}'
const res = await fetch('https://panel.ornek.com/api/v1/admin/services/529/cancel-refund', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ refund: 'credit', apply_on_module: true }),
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/services/529/cancel-refund');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'refund'          => 'credit',
        'apply_on_module' => true,
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Services()->CancelAndRefundService([
    'id'     => 529,
    'refund' => 'credit',
]);

// Istedigi iade YAPILMAMIS olabilir: karari 'refunded' verir, 'refund' degil.
$paid = $response['data']['refunded'] ?? false;

İptal Taleplerini Listeleme

get/api/v1/admin/services/cancellation-requests
Services/GetCancellationRequests admin sayfalı

Müşterilerin açtığı iptal taleplerini döndürür. Bekleyenler başta gelir.

Sorgu parametreleri 4
searchstringMüşteri adında, e-postasında, firmasında ve hizmet adında arar.
statusstringpending ya da approved.
pageintVarsayılan 1.
limitintVarsayılan 25, en çok 100.
Dönen alanlar data[] — 10
idintTalebin kimliği. Olay kimliğidir, hizmet kimliği değildir.
service_idintİptali istenen hizmetin kimliği.
user_idintTalebi açan müşterinin kimliği.
statusstringpending bekliyor, approved onaylanmış.
urgencystringnow hemen, period-ending dönem sonunda. Onayın ne yapacağını bu belirler.
reasonstringMüşterinin yazdığı gerekçe.
notestringMüşterinin iptal formuna yazdığı geri bildirim. Satır sonu içerebilen düz metin; müşteri bir şey yazmadıysa boş dize.
created_atstringTalebin açıldığı zaman.
serviceobjectHizmetin özeti.
idintHizmet kimliği.
namestringHizmet adı.
typestringHizmet tipi.
clientobjectTalebi açan müşteri.
idintMüşteri kimliği.
full_namestringAd ve soyad.
company_namestringFirma adı.
emailstringE-posta adresi. Yalnız detayda döner.
Meta 4
totalintSüzgece uyan toplam kayıt.
pageintBulunduğunuz sayfa.
limitintSayfa boyutu.
next_pageintSonraki sayfa. Sıfır son sayfada olduğunuz anlamına gelir.
Hatalar 1
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -G 'https://panel.ornek.com/api/v1/admin/services/cancellation-requests' \
  -H "Authorization: Bearer $API_KEY" \
  -d status=pending
const url = new URL('https://panel.ornek.com/api/v1/admin/services/cancellation-requests');
url.searchParams.set('status', 'pending');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.ornek.com/api/v1/admin/services/cancellation-requests?' . http_build_query(['status' => 'pending']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Services()->GetCancellationRequests([], ['status' => 'pending']);

İptal Talebi Detayı

get/api/v1/admin/services/cancellation-requests/{eid}
Services/GetCancellationRequest admin kalan hesaplanır

Tek bir talebi, kullanılan ve kalan dönemin hesabıyla birlikte döndürür.

Dönen alanlar data — 14
idintTalebin kimliği. Olay kimliğidir, hizmet kimliği değildir.
service_idintİptali istenen hizmetin kimliği.
user_idintTalebi açan müşterinin kimliği.
statusstringpending bekliyor, approved onaylanmış.
urgencystringnow hemen, period-ending dönem sonunda. Onayın ne yapacağını bu belirler.
reasonstringMüşterinin yazdığı gerekçe.
reason_keystringSeçilen gerekçenin makine anahtarı: not-needed, too-expensive, switching, missing-features ya da other. Gerekçe anahtarı kaydedilmeden önce açılmış taleplerde boştur.
reason_detailstringMüşterinin other gerekçesi için yazdığı serbest metin. Diğer gerekçelerde boştur.
notestringMüşterinin iptal formuna yazdığı geri bildirim; panel bunu Müşteri Geri Bildirimi olarak gösterir. Satır sonu içerebilen düz metin; müşteri bir şey yazmadıysa boş dize.
created_atstringTalebin açıldığı zaman.
serviceobjectHizmetin özeti.
idintHizmet kimliği.
namestringHizmet adı.
typestringHizmet tipi.
clientobjectTalebi açan müşteri.
idintMüşteri kimliği.
full_namestringAd ve soyad.
company_namestringFirma adı.
emailstringE-posta adresi. Yalnız detayda döner.
remainingobjectDönemin kullanılan ve kalan kısmı.
used_daysintDönemin kullanılmış gün sayısı.
remaining_daysintDönemden kalan gün sayısı.
remaining_amountfloatKalan güne düşen tutar. İade kararını verirken bakacağınız sayı budur.
approvedobject | nullOnay bilgisi: onaylayanın kimliği, adı ve zamanı. Talep beklerken boş döner.
Hatalar 2
not_found404İptal talebi bulunamadı.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl 'https://panel.ornek.com/api/v1/admin/services/cancellation-requests/91' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.ornek.com/api/v1/admin/services/cancellation-requests/91', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/services/cancellation-requests/91');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Iade karari icin kalan tutari BURADAN okuyun; iptal ucu bunu size sormaz.
$request = Api::Services()->GetCancellationRequest(['eid' => 91])['data'];
$owed    = $request['remaining']['remaining_amount'];

Talebi Onaylama

post/api/v1/admin/services/cancellation-requests/{eid}/accept
Services/AcceptCancellationRequest admin aciliyete göre davranır

Talebi onaylar. Aciliyet hemen ise hizmeti o anda iptal eder.

Gövde —
——Gövde gerekmez, boş gönderin. Aciliyet ve gerekçe, müşterinin kaydettiği talepten gelir; onay ikisini de değiştiremez.
Dönen alanlar data — 4
statusstringİşlem sonrası durum.
idintTalebin kimliği.
service_idintHizmet kimliği.
cancelled_nowboolHizmet bu istekte iptal edildi mi. Yanlış dönüyorsa iptal dönem sonuna bırakılmıştır.
Hatalar 4
not_found404Talep ya da hizmet bulunamadı.
already_approved422Talep zaten onaylanmış.
blocked_by_gate422gate:service.cancellation_accept kancası işlemi veto etti.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -X POST 'https://panel.ornek.com/api/v1/admin/services/cancellation-requests/91/accept' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.ornek.com/api/v1/admin/services/cancellation-requests/91/accept', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/services/cancellation-requests/91/accept');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Onay iade YAPMAZ. Para iadesi gerekiyorsa iptal-ve-iade ucunu ayrica cagirin.
$response = Api::Services()->AcceptCancellationRequest(['eid' => 91]);

$stoppedNow = $response['data']['cancelled_now'] ?? false;

Talebi Silme

delete/api/v1/admin/services/cancellation-requests/{eid}
Services/DeleteCancellationRequest admin

Talep kaydını siler. Hizmetin durumuna dokunmaz.

Dönen alanlar data — 2
deletedboolSilme başarılı mı.
idintSilinen talebin kimliği.
Hatalar 2
not_found404İptal talebi bulunamadı.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -X DELETE 'https://panel.ornek.com/api/v1/admin/services/cancellation-requests/91' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.ornek.com/api/v1/admin/services/cancellation-requests/91', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/services/cancellation-requests/91');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Talebi silmek 'reddetme' degildir: musteriye hicbir sey bildirilmez.
$response = Api::Services()->DeleteCancellationRequest(['eid' => 91]);

Hizmet Aboneliğini İptal Etme

post/api/v1/admin/services/{id}/cancel-subscription
Services/CancelServiceSubscription admin ödeme sağlayıcısında

Hizmete bağlı yinelenen ödeme aboneliğini ödeme sağlayıcısında iptal eder.

Gövde —
——Gövde gerekmez, boş gönderin. Abonelik hizmetten bulunur.
Dönen alanlar data — 3
statusstringİşlem sonrası abonelik durumu.
subscription_idintAboneliğin kimliği.
service_idintHizmet kimliği.
Hatalar 4
not_found404Hizmet bulunamadı.
subscription_not_found422Hizmette abonelik yok.
subscription_cancel_failed500Ödeme sağlayıcısı aboneliği iptal edemedi.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -X POST 'https://panel.ornek.com/api/v1/admin/services/529/cancel-subscription' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.ornek.com/api/v1/admin/services/529/cancel-subscription', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/services/529/cancel-subscription');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Abonelik iptali HIZMETI iptal etmez: tahsilat durur, hizmet calismaya devam eder.
Api::Services()->CancelServiceSubscription(['id' => 529]);
Api::Services()->CancelService(['id' => 529]);

Ek Hizmet Aboneliğini İptal Etme

post/api/v1/admin/services/{id}/addons/{addon_id}/cancel-subscription
Services/CancelServiceAddonSubscription admin ödeme sağlayıcısında

Ek hizmete bağlı yinelenen ödeme aboneliğini iptal eder.

Gövde —
——Gövde gerekmez, boş gönderin. Abonelik hizmet ve ek hizmet kaydından bulunur.
Dönen alanlar data — 3
statusstringİşlem sonrası abonelik durumu.
subscription_idintAboneliğin kimliği.
addon_idintEk hizmet kaydının kimliği.
Hatalar 4
not_found404Hizmet ya da ek hizmet bulunamadı.
subscription_not_found422Ek hizmette abonelik yok.
subscription_cancel_failed500Ödeme sağlayıcısı aboneliği iptal edemedi.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -X POST 'https://panel.ornek.com/api/v1/admin/services/529/addons/44/cancel-subscription' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.ornek.com/api/v1/admin/services/529/addons/44/cancel-subscription', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/services/529/addons/44/cancel-subscription');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Services()->CancelServiceAddonSubscription([
    'id'       => 529,
    'addon_id' => 44,
]);

Hizmeti Abonelikten Çıkarma

post/api/v1/admin/services/{id}/remove-subscription
Services/RemoveServiceFromSubscription abonelik yaşar

Tek bir hizmeti abonelikten çıkarır; aboneliğin diğer üyeleri kalır.

Gövde —
——Gövde gerekmez, boş gönderin. Hizmet adresteki kimlikten belirlenir.
Dönen alanlar data — 4
statusstringÇıkarma sonucu.
subscription_statusstringAboneliğin çıkarma sonrası durumu. Son üye de çıkınca abonelik iptale döner.
subscription_idintHizmetin ayrıldığı abonelik.
service_idintÇıkarılan hizmet.
Hatalar 3
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
not_found404Hizmet bulunamadı.
subscription_not_found422Hizmet bir aboneliğe bağlı değil.
İstek
curl -X POST 'https://panel.ornek.com/api/v1/admin/services/482/remove-subscription' \
  -H "Authorization: Bearer $ADMIN_KEY"
const res = await fetch(`https://panel.ornek.com/api/v1/admin/services/${serviceId}/remove-subscription`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${adminKey}` },
});

const { data } = await res.json();
if (data.subscription_status === 'cancelled') refreshAgreement();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/services/' . $serviceId . '/remove-subscription');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $adminKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// CIKARMA ile IPTAL farklidir: bu cagri yalniz bu hizmeti alir, abonelik digerleriyle surer.
// Odeme tarafi da yeniden fiyatlanir; tum anlasmayi bitirmek icin cancel-subscription kullanin.
$r = Api::Services()->RemoveServiceFromSubscription(['id' => $serviceId])['data'];

Tuzaklar

Abonelik iptali hizmeti kapatmaz

Abonelik uçları yalnız ödeme sağlayıcısındaki yinelenen tahsilatı durdurur. Hizmet çalışmaya, dönemi dolunca yenileme faturası kesilmeye devam eder; müşteri artık otomatik ödemediği için fatura ödenmeden kalır. Hizmetin de bitmesi gerekiyorsa iptal ucunu ayrıca çağırın.

Onaylamak iade etmez

İptal talebini onaylamak hizmeti kapatır ama para iade etmez. Kullanılmamış dönemi geri vermek istiyorsanız iptal-ve-iade ucunu ayrıca çağırmanız gerekir; kalan tutarı talep detayındaki hesaptan okursunuz.

İade istemek iade edildiği anlamına gelmez

Gövdedeki refund alanı ne istediğinizi söyler; gerçekte ne olduğunu yanıttaki refunded söyler. Kalan bakiye yoksa iade yapılmaz ve istek yine de 200 döner. İki alanı karıştırmak müşteriye yapılmamış bir iadeyi bildirmeye yol açar.

Atlama bir hata değildir

renewal_skipped, isteğinizin bozuk olduğunu değil, o hizmet için şu an fatura kesilmemesi gerektiğini söyler: dönem zaten faturalanmış, hizmette yenileme faturası kapatılmış ya da veri eksik olabilir. Sebep mesajda yazar; yeniden denemek yardımcı olmaz.

Talep uçları olay kimliği ister

İptal talebi uçlarındaki kimlik talebin kimliğidir, hizmetin değil. Listede id talebe, service_id hizmete aittir; hizmet kimliğini vermek 404 döndürür.

Faydalı oldu mu?

Geri bildiriminiz için teşekkürler!

Hâlâ Yardıma mı İhtiyacınız Var?

Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.