Faturalama Sisteminizi Bir Öğleden Sonrada Bağlayın

Bu sayfa, merchant-provider/v1 entegrasyonunun kısa yoludur: neyi, hangi sırayla geliştireceğinizi, her parçayı kendi makinenizde nasıl test edeceğinizi ve nasıl canlıya geçeceğinizi anlatır. Şirketinin müşterileri, ödemeleri ve abonelikleri kendi faturalama sisteminde (ya da bu sistemin bağlı olduğu birkaç ödeme sağlayıcısında) tutulan mühendisler için hazırlanmıştır. Kuralların tamamı Kendi faturalama sisteminizi bağlamak sayfasında, tüm istek ve yanıtlar da Örneklerle REST bağlantısı sayfasındadır.

Ne Geliştiriyorsunuz

Faturalama sisteminizin önünde duran küçük bir HTTPS API'si. Bu API'yi Chargeless çağırır; API'niz ise Chargeless'ı hiçbir zaman çağırmaz (sonuç bildirimleri, yani callback'ler hariç; onlar da isteğe bağlıdır).

text
customer ──► Chargeless ──(signed HTTPS)──► your API ──► your billing system
             decides by                     reads facts,
             your policy                    executes approved
                                            refunds and cancellations
  • Kararı Chargeless verir. Her iade ve iptal kararını, Chargeless'ta tanımladığınız politika (süre sınırları, tutar üst sınırları, hız sınırları, kendi kurallarınız) belirler. API'niz hiçbir zaman karar vermez; bilgileri bildirir ve onaylanan işlemi uygular.
  • Her çağrı imzalıdır; imza, yalnızca sizin ve Chargeless'ın bildiği bir gizli anahtarla atılır. Her iade ve iptal bir idempotency anahtarı taşır; böylece yeniden denenen bir çağrı hiçbir zaman iki kez ödeme yapmaz.
  • API'nizi hiçbir dil modeli çağırmaz. Çağrılar, karar kaydedildikten sonra Chargeless'ın kendi kodundan gelir.

API on operasyondan oluşur; başlamak için yedisi yeterlidir:

Sıra Operasyon REST Ne yapar
1 describe GET /v1/describe Neleri ve hangi para birimlerinde desteklediğinizi bildirir
2 find_customers POST /v1/customers/search Müşterileri e-posta, telefon, sipariş, ödeme ya da kartın son dört hanesiyle bulur
2 get_customer GET /v1/customers/{customer_ref} Tek bir müşteriyi son iadeleri ve ters ibrazlarıyla döndürür
2 list_transactions GET /v1/customers/{customer_ref}/transactions Bir müşterinin son ödemelerini ve aboneliklerini döndürür
2 get_transaction GET /v1/transactions/{transaction_ref} Tek bir ödemeyi iadeleriyle döndürür
3 refund POST /v1/refunds Onaylanan tutarı orijinal ödeme yöntemine iade eder
3 get_operation GET /v1/operations/{idempotency_key} Chargeless'ın gönderdiği bir anahtarla ne yapıldığını bildirir
4 get_subscription GET /v1/subscriptions/{subscription_ref} Tek bir aboneliği döndürür (yalnızca iptal destekleniyorsa)
4 cancel_subscription POST /v1/subscriptions/{subscription_ref}/cancel Onaylanan bir aboneliği iptal eder (isteğe bağlı)
sonra list_payment_attempts POST /v1/payment-attempts/list İçgörüler sayfası için kartla ödeme denemelerini listeler (isteğe bağlı)

Sisteminiz zaten MCP kullanmıyorsa REST'i seçin: düz HTTP'dir ve curl ile test edebilirsiniz. MCP bağlantısı aynı operasyonları ve kuralları araç (tool) olarak sunar.

Başlamadan Önce

  • Sözleşme dosyaları. merchant-provider-v1-contract.zip dosyasını indirin: OpenAPI tanımı, her nesne için bir JSON Schema, her nesnenin geçerli örnekleri ve MCP profili bu dosyadadır. Şemaları testlerinize yükleyin: örnekler, Chargeless'ın kabul ettiği yanıtlardır.
  • Uyumluluk kiti. Bilgisayarınıza uygun providercheck dosyasını providercheck sayfasından indirin.
  • Faturalama sisteminizin bir sandbox'ı (test ortamı); orada iade ve iptal hiçbir maliyet doğurmaz.
  • Aşağıdaki örnek sunucuyu çalıştırmak istiyorsanız Node 18 veya üzeri; imzalı istekler için curl ve openssl.

Beş Dakikada: Çalışan Bir Sunucunun Kontrollerden Geçişini İzleyin

Kontrollerden zaten geçen bir sunucuyla başlayın; böylece başarılı bir çalıştırmanın neye benzediğini görürsünüz. Örneklerle REST bağlantısı sayfasındaki eksiksiz sunucuyu server.mjs olarak kaydedin ve uydurma bir sandbox imzalama anahtarıyla çalıştırın:

sh
SIGNING_SECRET=srmps_local_0123456789abcdef PORT=8080 node server.mjs

Başka bir terminalde kiti bu sunucuya karşı çalıştırın (-allow-private, kitin localhost'ta düz http kullanmasına izin verir):

sh
export PROVIDERCHECK_SANDBOX_SIGNING_SECRET=srmps_local_0123456789abcdef
./providercheck -sandbox -allow-private -base-url http://localhost:8080 \
  -tenant 0199a3c1-0a0b-7c0d-8e0f-101112131415 \
  -customer cus_1001 -transaction ch_1001 -subscription sub_1001

Kit her kontrol için bir satır yazar ve PASSED ile biter. Yeniden çalıştırmadan önce sunucuyu yeniden başlatın: kit gerçekten iade ve iptal yapar. Bu sunucuyu geliştirerek kendi sunucunuza dönüştürebilir (bellekteki depoyu faturalama sisteminize yapılan çağrılarla değiştirip kuralları koruyarak) ya da istediğiniz bir dilde kendi sunucunuzu yazabilirsiniz.

İmzalı İstek Gönderen curl

Her istek imzalı olmalıdır; bu yüzden düz curl 401 alır. Aşağıdaki kabuk fonksiyonu bir isteği Chargeless'ın imzaladığı şekilde imzalar; bash ve zsh'de çalışır:

sh
# srcurl METHOD PATH [BODY] [IDEMPOTENCY_KEY]: one call to your endpoint, signed as Chargeless signs it.
# Set SR_BASE to your base URL (https://billing.example.com/supportroute, or http://localhost:8080)
# and SR_SECRET to the signing secret your endpoint verifies with.
srcurl() {
  local method=$1 target=$2 body=${3-} key=${4-}
  local rest=${SR_BASE#*://}
  local host=${rest%%/*}
  local prefix=${rest#"$host"}; prefix=${prefix%/}
  local ts sig
  local -a extra=()
  [ -n "$key" ] && extra+=(-H "Idempotency-Key: $key")
  [ -n "$body" ] && extra+=(-H 'Content-Type: application/json' --data-binary "$body")
  ts=$(date +%s)
  sig=$(printf '%s\n%s\n%s\n%s\n%s\n%s' "$ts" "$method" "$host" "$prefix$target" "$key" "$body" \
    | openssl dgst -sha256 -hmac "$SR_SECRET" -hex | sed 's/^.*= *//')
  curl -sS -X "$method" "${SR_BASE%%://*}://$host$prefix$target" \
    -H "X-SupportRoute-Timestamp: $ts" -H "X-SupportRoute-Signature: v1=$sig" "${extra[@]}" \
    -w '\nHTTP %{http_code}\n'
}
export SR_BASE=http://localhost:8080 SR_SECRET=srmps_local_0123456789abcdef

Her yanıtı görmek için bu fonksiyonu önce örnek sunucuya, sonra kendi sunucunuza karşı kullanın.

Adım 1: İmzaları Doğrulayın, describe Çağrısını Yanıtlayın

İşe bununla başlayın: imzalı bir describe çağrısı yanıtlanana kadar başka hiçbir çağrı yapılmaz.

  1. Önce ham istek baytlarını okuyup imzayı doğrulayın: herhangi bir şeyi ayrıştırmadan (parse) önce X-SupportRoute-Signature başlığını doğrulayın. İmza, altı satırın (zaman damgası, yöntem, host, yol, idempotency anahtarı, gövde) HMAC-SHA256 değeridir; sabit zamanlı (constant time) olarak karşılaştırılır ve zaman damgası saatinizden en fazla beş dakika sapabilir. Adım adım imzalama bölümünde imzalanan dizenin tam hali, iki test vektörü ve bir Node doğrulayıcısı bulunur. Yanlış imzaya 401 dönün.
  2. describe çağrısını desteklediklerinizle yanıtlayın. Az ve gerçeğe uygun bildirerek başlayın: partial_refunds değerini yalnızca bir ödemenin bir kısmını iade edebiliyorsanız bildirin; 4. adıma kadar cancel_subscription: false olarak bırakın.

Test edin:

sh
srcurl GET /v1/describe                    # 200 and your describe
SR_SECRET=wrong srcurl GET /v1/describe    # 401 credentials_rejected

Bir proxy ya da yük dengeleyicinin (load balancer) arkasındaysanız imzayı, sunucunuzun gördüğü iç host adıyla değil, Chargeless'ın çağırdığı herkese açık host adıyla doğrulayın; yolu da gönderildiği haliyle, taban yol (base path) dahil kullanın.

Adım 2: Okuma Operasyonları

find_customers, get_customer, list_transactions ve get_transaction operasyonlarını uygulayın. Müşteri sohbette, bir talepte ya da portalda size ulaştığında okunan veriler bunlardır; bu yüzden her birinin yanıt süresini bir saniyenin altında tutun (sözleşme kontrolü 2,5 sn'den uzun süren bir okumayı başarısız sayar).

Sözleşme kontrolünün en sık yakaladığı hatalar:

  • Tutar, para birimiyle birlikte en küçük birim (minor unit) cinsinden bir tamsayıdır: {"amount_minor": 4999, "currency": "USD"}. Asla 49.99, 4999.0 ya da "4999" değil. JPY'nin alt birimi yoktur, KWD'nin ise üç basamaklı alt birimi vardır.
  • Her anahtar (key) yanıtta yer alır; değeri bilmiyorsanız null gönderin. Eksik bir anahtar yanıtın tamamını geçersiz kılar ve kontrol eksik anahtarın adını verir: `amount.amount_minor` is missing.
  • Referanslar harf, rakam, ., _, : ve - karakterlerinden oluşur, 1 ile 128 karakter uzunluğundadır ve hiçbir zaman ardışık 13 veya daha fazla rakam içermez; böyle bir dizi kart numarasına benzer. Sayısal kimlikleri kodlayın (ord_2026101500012 reddedilir; ord-2026-10-15-0001 uygundur). Bkz. Referanslar.
  • Eşleşme bulunmaması hata değildir: find_customers, {"candidates": []} gövdesiyle 200 döner. Diğer okuma operasyonlarında bilinmeyen bir müşteri ya da ödeme için 404 not_found dönülür.
  • Bir ödeme, gerçekleşen tüm iadelerini listeler; her iadeyi Chargeless yaptıysa Chargeless'ın idempotency anahtarıyla, yapmadıysa null ile.

Test edin:

sh
srcurl POST /v1/customers/search '{"email":"[email protected]"}'
srcurl GET /v1/customers/cus_1001
srcurl GET /v1/customers/cus_1001/transactions
srcurl GET /v1/transactions/ch_1001
srcurl GET /v1/transactions/does_not_exist     # 404 not_found

Her yanıtı sözleşme zip'indeki ilgili örnekle (schemas/merchant-provider/examples/v1/) karşılaştırın ya da kullandığınız teknolojinin JSON Schema kütüphanesiyle (draft 2020-12, biçim (format) denetimi açık) doğrulayın; bunun için schemas/merchant-provider/v1/ altındaki her dosyayı kendi $id değeriyle yükleyin.

Adım 3: İadeler ve get_operation

Para hareketi bu adımda gerçekleşir; bu yüzden kuralların çoğu buradadır.

  1. Deneme çalıştırmaları (dry run). "dry_run": true içeren bir gövde idempotency anahtarı taşımaz. Gerçek bir iadede yapacağınız tüm kontrolleri yapın ve would_succeed ya da vereceğiniz reddi döndürün. Hiçbir şeyi değiştirmeyin, hiçbir şey saklamayın.
  2. Anahtarlar. Gerçek bir iade isteği Idempotency-Key başlığıyla gelir. Anahtarı, isteği ve sonucunu ödeme işlemcinizi (processor) çağırmadan önce, tek bir veritabanı işleminde (transaction) saklayın ve en az 30 gün tutun.
    • Aynı anahtar aynı gövdeyle yeniden gelirse saklanan sonucu döndürün; hiçbir zaman iki kez iade yapmayın.
    • Aynı anahtar farklı bir tutar ya da ödemeyle gelirse 409 idempotency_conflict dönün ve hiçbir işlem yapmayın.
    • İlk çağrı hâlâ sürerken aynı anahtar gelirse 409 in_progress dönün.
  3. Fazla iadeyi siz de kontrol edin. Ödemede kalan tutardan fazlasını, Chargeless bunu kontrol etmiş olsa bile 422 amount_exceeds_refundable ile reddedin: bu arada ödeme başka bir kanaldan iade edilmiş olabilir.
  4. Retler. 422, bu anahtarla işlemi hiçbir zaman yürütmeyeceğiniz anlamına gelir. Kayıtlarınız istekle çeliştiğinde durum kodlarını (already_refunded, not_refundable, …), işlemi kendi kuralınız durdurduğunda ise bir koruma (guard) kodunu ya da kendi x_… kodunuzu kullanın. Bkz. Retler.
  5. get_operation, aldığınız her anahtar için yanıt verir: succeeded, pending, failed (ret bilgisiyle) ve yalnızca hiç almadığınız bir anahtar için unknown. Hiçbir zaman 404 dönmez.
  6. Anahtarı ödemede gösterin. İadeden sonra get_transaction, iadeyi refunds[] içinde anahtarıyla, bayt bayt aynı olarak listeler.

Test edin:

sh
REFUND='{"transaction_ref":"ch_1001","amount":{"amount_minor":150,"currency":"USD"},"reason":"duplicate","dry_run":false}'
KEY=0199a3c1-0a0b-7c0d-8e0f-101112131415:walkthrough:refund:1

srcurl POST /v1/refunds "${REFUND/false/true}"   # a dry run: 200 would_succeed, nothing changes
srcurl POST /v1/refunds "$REFUND" "$KEY"         # 200 succeeded (or pending)
srcurl POST /v1/refunds "$REFUND" "$KEY"         # the same result again, no second refund
srcurl POST /v1/refunds "${REFUND/150/250}" "$KEY"   # 409 idempotency_conflict
srcurl GET "/v1/operations/$KEY"                 # 200 succeeded, with the result
srcurl GET /v1/transactions/ch_1001              # refunds[] lists it under $KEY

Adım 4: İptaller (İsteğe Bağlı)

Müşterileriniz aboneliklerini iptal edebiliyorsa get_subscription ve cancel_subscription operasyonlarını uygulayın, ardından describe yanıtında cancel_subscription: true bildirin (dönem sonunda iptal edebiliyorsanız cancel_at_period_end: true de). Anahtarlar, deneme çalıştırmaları, tekrar gönderimler (replay) ve çakışmalar iadelerdekiyle tamamen aynı şekilde işler; zaten iptal edilmiş bir abonelik için 422 already_canceled dönülür.

sh
srcurl GET /v1/subscriptions/sub_1001
srcurl POST /v1/subscriptions/sub_1001/cancel '{"at_period_end":true,"reason":"forgot_to_cancel","dry_run":true}'

Adım 5: Kiti Sandbox'ınıza Karşı Çalıştırın

API'nizi faturalama sisteminizin sandbox'ının önüne kurun, iade edilebilir bir ödemesi (iptal destekliyorsanız etkin bir aboneliği de) olan yeni bir sandbox müşterisi seçin ve kiti providercheck sayfasında anlatıldığı gibi çalıştırın. Kit gerçekten en küçük birimden 1 birim iade eder ve aboneliği iptal eder; canlı bir sistemde bunlar para hareketi olmadan gösterilemez. Kit, bağlantınızı ilk kez kaydettiğinizde Chargeless'ın gösterdiği sandbox imzalama anahtarını (srmps_…) kullanır (6. adım); bu yüzden önce 6. adımı tamamlayıp buraya geri dönebilirsiniz.

Başarısız her satırda kontrolün adı, bir hata kodu ve istek kimliği (request id) yer alır; böylece çağrıyı kendi günlüklerinizde bulabilirsiniz. Hatayı düzeltin, yeni test verileri (fixture) seçin, çalıştırma PASSED ile bitene kadar tekrarlayın ve rapor dosyasını saklayın.

Adım 6: Bağlantıyı Panelde Kurun

  1. Bağlantıyı ekleyin. Chargeless panelinde Ayarlar → Entegrasyonlar'ı açın ve Ödemeler altındaki Kendi ödeme sisteminiz kartında Bağlan'ı seçin. Bağlantıya bir ad verin ve sisteminizin mutabakat para birimini seçin.
  2. Canlı uç noktanızı girin. Taban URL'yi (443 portunda https://…, herkese açık bir sertifikayla, yönlendirme (redirect) olmadan), REST ya da MCP seçimini ve gerekiyorsa ağ geçidinizin (gateway) istediği bearer token'ı ya da edge başlıklarını girin. Siz yazarken panel, Chargeless'ın çağıracağı tüm URL'leri listeler.
  3. İmzalama anahtarlarını kaydedin. İlk kayıtta iki anahtar yalnızca bir kez gösterilir:
    • srmp_…, imzalama anahtarı: canlı API'niz imzaları bununla doğrular;
    • srmps_…, sandbox imzalama anahtarı: bununla yalnızca sandbox'ınız doğrulama yapar; canlı API'niz bu anahtarı reddetmelidir. Kit istekleri bu anahtarla imzalar.
  4. Chargeless'ın adreslerine izin verin. Güvenlik duvarınız yalnızca izin listesindeki (allowlist) adreslerden gelen çağrıları kabul ediyorsa, aynı sayfadaki Çıkış (Egress) bölümünde listelenen tüm adresleri ekleyin.
  5. Test nesnelerini seçin. Canlı sisteminizden az işlem gören bir müşteri, iade edilebilir bir ödeme ve iptal destekliyorsanız etkin bir abonelik seçin. Sözleşme kontrolü bunları okur ve yalnızca deneme çalıştırmaları gönderir: hiçbir şey iade ya da iptal edilmez.
  6. Bağlantıyı test edin. "Bağlantıyı Test Et", sözleşme kontrolünü Chargeless'ın kendi ağından canlı uç noktanıza karşı çalıştırır. Başarısız her satırda uç nokta, hatalı bir yanıtta da ilgili alan belirtilir: düzeltin ve yeniden test edin.
  7. Kitin raporunu Uyumluluk kiti bölümüne yükleyin: 5. adımdaki dosyayı değiştirmeden.
  8. Canlıya geçin. Bir politika yayımlayın, devredilen vakaların nereye gideceğini seçin ve kurulum kontrol listesinden canlıya geçin. Canlıya geçiş sırasında sözleşme kontrolü bir kez daha çalışır.

Sık Karşılaşılan Hatalar

Gördüğünüz Nedeni Çözüm
describe, signature_not_verified ile başarısız oluyor Yanlış imzalı isteği kabul ediyorsunuz Her isteğin imzasını, başka her şeyden önce doğrulayın
Proxy arkasında her çağrı 401 alıyor Proxy Host başlığını ya da yolu değiştiriyor Herkese açık host adıyla ve yolu gönderildiği haliyle doğrulayın
`amount.amount_minor` must be an integer, not a string ile schema_invalid Ondalıklı ya da tırnak içinde yazılmış bir tutar En küçük birim cinsinden bir tamsayı gönderin
`…` is missing ile schema_invalid Yanıtta eksik bir anahtar var Her anahtarı gönderin; değer bilinmiyorsa null
card_number_in_field Ardışık 13 veya daha fazla rakam içeren bir referans Sayısal kimlikleri kodlayın (base32, base62)
fixture_not_found Test nesnesi, Chargeless'ın çağırdığı sistemde yok Sözleşme kontrolü için canlı sistemdeki, kit için sandbox'taki nesneleri kullanın
refunds_exceed_amount, fixture_not_refundable Test ödemesi iade edilmiş, itiraz edilmiş ya da başarısız olmuş İade edilebilir tutarı kalan, başarılı bir ödeme seçin
over_refund_not_refused API'niz kalan tutardan fazlasını iade edecekti 422 amount_exceeds_refundable ile reddedin
dry_run_changed_state Bir deneme çalıştırması gerçekten yürütüldü Deneme çalıştırmasını hiçbir zaman yürütmeyin ve saklamayın
retryable_mismatch Bir hatanın retryable değeri durum koduyla çelişiyor 400, 401, 403, 404, çakışma için 409 ve 422'de false; işlem sürerken dönen 409, 429 ve 5xx'te true
not_unknown get_operation, hiç gönderilmemiş bir anahtar için 404 döndü "status": "unknown" ile 200 dönün
latency_budget_exceeded Bir okuma 2,5 sn'den, bir deneme çalıştırması 10 sn'den uzun sürdü Yanıtı hızlandırın; soğuk başlangıç (cold start) bir kez başarısız olabilir, yeniden test edin

Canlıya Geçtikten Sonra

  • Müşteriler sohbetten, e-postayla, yardım sitenizden ya da yardım masanız üzerinden başvurur; Chargeless API'nizden bilgileri okur, politikanıza göre karar verir ve refund ya da cancel_subscription çağrısını yalnızca onayladığı işlemler için yapar.
  • Politikanızın izin vermediği ve API'nizin bir koruma koduyla reddettiği her işlem, ilgili bilgilerle birlikte ekibinize devredilir.
  • Ayarlar → bağlantınız → Sağlayıcı Durumu ve çağrı kaydı, her çağrıyı istek kimliğiyle gösterir. Çağrılar reddedildiğinde ya da başarısız olduğunda Chargeless çalışma alanınızın sahiplerine, yöneticilerine ve geliştiricilerine e-posta gönderir.