Chargeless API'si: Arka Ucunuz için

Bu kılavuz, Chargeless'ı kendi sunucularınızdan çağıran mühendisler içindir. API ile sitenizde oturum açmış bir müşteri adına iade ya da iptal yapabilir, kendi destek formunuza gelen talepleri iletebilir veya politikayı, işlemleri ve vakaları kendi sistemlerinize aktarabilirsiniz.

Chargeless her iade ve iptal kararını, panelde yayımladığınız politikaya göre verir. Arka ucunuz (backend) bir işlem önerir; Chargeless, tıpkı sohbet widget'ında olduğu gibi, bu işlem hakkında karar verir, işlemi ödeme sağlayıcınızda gerçekleştirir ve kaydeder. Hiçbir çağrı politikayı, güvenlik limitlerini ya da devredeki bir acil durdurmayı aşamaz.

Dosya İçeriği
openapi/backend-api/v1.yaml OpenAPI 3.1 biçiminde API: aşağıdaki tüm prosedürler, istekler ve yanıtlar, alanlarıyla birlikte
proto/sr/**/v1/*.proto Aynı API'nin Protocol Buffers karşılığı; tipli bir istemci üretmek için (aşağıda)
CHANGELOG.md Sözleşmelerdeki (contracts) tüm değişiklikler

Tüm prosedürler, alanları ve örnek yanıtlarıyla birlikte API başvurusunda yer alır. İlgili kılavuzlar: Chargeless webhook'larını almak (çağrınızdan sonra neler olduğu), widget ve müşteri kimliği (imzalı kimlik token'ı) ve Kendi faturalama sisteminizi bağlamak (ters yön: Chargeless'ın sizin sisteminizi çağırması).

1. Temel Bilgiler

API Anahtarınız

Ayarlar → API Anahtarları bölümünden bir anahtar oluşturun (sahipler, yöneticiler ve geliştiriciler oluşturabilir). Anahtar sr_live_ ile, test çalışma alanında (aşağıda) ise sr_test_ ile başlar ve yalnızca bir kez gösterilir. Anahtarı sunucunuzun gizli bilgi deposunda (secret store) saklayın; tarayıcıya, bir uygulamaya ya da kod deposuna (repository) asla koymayın. Her çağrıda şu başlıkla gönderin:

Authorization: Bearer sr_live_…

Her anahtar tek bir çalışma alanına aittir; bu yüzden API'nin hiçbir yerinde tenant ya da çalışma alanı belirten bir alan yoktur. Anahtarları aynı yerden iptal edebilirsiniz (revoke); Son kullanım sütunu hangi anahtarların hâlâ kullanıldığını gösterir.

Bir anahtarla şunları yapabilirsiniz: müşterileri doğrulayıp ödemelerini ve aboneliklerini sorgulamak; iade ve iptal işlemleri göndermek; kendi formunuza gelen talepleri iletmek; politikayı okumak ve bir kararın önizlemesini almak; işlemleri, vakaları, iadeleri, itirazları, dolandırıcılık uyarılarını, abonelikleri ve sağlayıcı durumunu okumak. Şunları yapamazsınız: panelde oturum açmak, politikayı yayımlamak; ayarları, ekibi, anahtarları ya da gizli bilgileri değiştirmek; talepleri okumak veya yanıtlamak; politikayı, güvenlik limitlerini ya da bir acil durdurmayı aşmak. Chargeless çalışma alanınızı askıya almışsa GetTenant dışındaki tüm çağrılar reddedilir.

Test Anahtarları ve Test Çalışma Alanları

Entegrasyonunuzu bir test çalışma alanında kurup deneyin. Çalışma alanı menüsünden (Çalışma Alanı Oluştur) Test çalışma alanı anahtarını açarak bir tane oluşturun. Test çalışma alanı diğer çalışma alanları gibi çalışır: kendi politikası, yardım sitesi, widget'ı, webhook'ları ve ekibi vardır; aynı prosedürler, kararlar ve güvenlik limitleri geçerlidir. İki fark vardır:

  • API anahtarları sr_test_ ile başlar.
  • Yalnızca test modundaki ödeme hesapları bağlanabilir: Stripe test anahtarları, bir Paddle test ortamı (sandbox), test modunda FastSpring, bir Adyen test hesabı, dLocal test ortamı ve bir Ecommpay test projesi. Canlı bir hesap failed_precondition ile reddedilir ve hiçbir bilgi saklanmaz. Kendi faturalama sisteminizi her zamanki gibi bağlayabilirsiniz; bağlantıyı test sisteminize yönlendirin.

Test çalışma alanındaki iadeler ve iptaller sağlayıcınızın test ortamında (sandbox) gerçekleşir; böylece sürecin tamamını (karar, yürütme, sonuç ve webhook'lar) gerçek para kullanmadan izleyebilirsiniz. Test çalışma alanını da canlı çalışma alanında yapacağınız gibi canlıya alın (ana sayfasındaki Canlıya Al): ikisinde de işlemler yalnızca canlıya geçtikten sonra çalışır.

Bir çalışma alanının test mi canlı mı olduğu oluşturulduğu anda belirlenir ve sonradan değişmez. Bir sr_test_ anahtarı yalnızca kendi test çalışma alanına erişir: üretime (production) geçtiğinizde canlı çalışma alanına ait bir sr_live_ anahtarı kullanın. GetTenant, test çalışma alanları için "test": true döndürür.

Bir Prosedürü Çağırmak

API, HTTPS üzerinden Connect protokolünü kullanır: HTTP üzerinden düz JSON; özel bir istemci gerekmez. Her prosedür, JSON gövdesinin şu adrese POST ile gönderilmesiyle çağrılır:

https://api.chargeless.io/{package}.{Service}/{Method}

İstekte Content-Type: application/json başlığı bulunur. Çalışma alanınızı okuyan ilk çağrı:

sh
curl -sS https://api.chargeless.io/sr.tenant.v1.TenantService/GetTenant \
  -H "Authorization: Bearer $CHARGELESS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

JSON, Protocol Buffers JSON eşlemesine uyar:

  • Alan adları lowerCamelCase'tir (proto'daki customer_ids, JSON'da customerIds olur).
  • Enum'lar adlarıyla, string olarak yazılır: "ACTION_TYPE_REFUND".
  • 64 bitlik tamsayılar string'dir: "amountMinor": "1999" (girdide sayı da kabul edilir).
  • Zamanlar UTC cinsinden RFC 3339 string'leridir: "2026-11-06T09:30:00Z".
  • Para tutarı her zaman en küçük birim (kuruş, cent) cinsinden bir değer ve bir ISO 4217 kodudur: {"amountMinor": "1999", "currency": "USD"} 19,99 USD, {"amountMinor": "1500", "currency": "JPY"} 1.500 JPY'dir. Kayan noktalı sayı (float) asla kullanılmaz.
  • Kimlikler (id) opak string'lerdir. API, defterin (ledger) kimliklerini (bir ödeme kaydı, bir abonelik, bir işlem) döndürür ve isteklerde de bunları bekler; sağlayıcınızın kendi kimlikleri yalnızca ilgili alan bunu belirtiyorsa kabul edilir.
  • Göndermediğiniz alanlar varsayılan değerlerini alır; Chargeless'ın tanımadığı alanlar yok sayılır. Yanıtlar varsayılan değerdeki (boş, sıfır, false) alanları içermez; eksik bir alanı varsayılan değerinde kabul edin.
  • bytes alanları base64 ile kodlanmış olarak gelir; GetPublished'ın döndürdüğü politika belgesi de böyle bir alandır.

Aynı çağrı, aşağıda anlatılan yeniden denemelerle birlikte Node (18 veya üzeri, ek paket gerekmez) ve Go ile:

js
// chargeless.mjs
const API = 'https://api.chargeless.io';
const RETRY = new Set(['unavailable', 'deadline_exceeded', 'internal', 'resource_exhausted']);

export async function call(procedure, body = {}) {
  for (let attempt = 0; ; attempt++) {
    let res;
    try {
      res = await fetch(`${API}/${procedure}`, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${process.env.CHARGELESS_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(body),
      });
    } catch (err) {
      if (attempt >= 4) throw err; // a network error: send the same request again
      await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
      continue;
    }
    // An error body that is not JSON (a proxy in between) is read from its status.
    const answer = await res.json().catch(() => ({
      code: res.status === 429 ? 'resource_exhausted' : res.status >= 500 ? 'unavailable' : 'unknown',
      message: res.statusText,
    }));
    if (res.ok) return answer;
    if (!RETRY.has(answer.code) || attempt >= 4) {
      throw Object.assign(new Error(`${procedure}: ${answer.code}: ${answer.message}`), answer);
    }
    const wait = Number(res.headers.get('Retry-After') ?? 0) * 1000;
    await new Promise((r) => setTimeout(r, Math.max(wait, 1000 * 2 ** attempt)));
  }
}

// const { tenant } = await call('sr.tenant.v1.TenantService/GetTenant');
go
// A plain net/http call; section 5 shows a generated, typed client.
func call(ctx context.Context, procedure string, in, out any) error {
    body, err := json.Marshal(in)
    if err != nil {
        return err
    }
    req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://api.chargeless.io/"+procedure, bytes.NewReader(body))
    if err != nil {
        return err
    }
    req.Header.Set("Authorization", "Bearer "+os.Getenv("CHARGELESS_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    if err != nil {
        return err
    }
    defer res.Body.Close()
    if res.StatusCode != http.StatusOK {
        var e struct{ Code, Message string }
        _ = json.NewDecoder(res.Body).Decode(&e)
        return fmt.Errorf("%s: %s: %s", procedure, e.Code, e.Message)
    }
    return json.NewDecoder(res.Body).Decode(out)
}

Hatalar

Başarısız bir çağrı, 2xx dışında bir durum kodu ve şu biçimde bir JSON gövdesi döndürür:

json
{"code": "failed_precondition", "message": "…", "details": [ … ]}
code HTTP Ne yapmalısınız
invalid_argument 400 İstek hatalı biçimlendirilmiş; hangi alanın hatalı olduğunu mesaj belirtir. İsteği değiştirmeden yeniden denemeyin.
failed_precondition 400 İstek doğru biçimlendirilmiş ama şu anda uygulanamıyor (başka bir amaç için yeniden kullanılmış bir idempotency anahtarı, var olmayan bir hedef, canlıya geçmemiş bir çalışma alanı). Nedeni details belirtir.
unauthenticated 401 Anahtar eksik, iptal edilmiş ya da yanlış yazılmış.
permission_denied 403 API anahtarları bu prosedürü çağıramaz.
not_found 404 Çalışma alanınızda böyle bir nesne yok.
already_exists 409 Nesne zaten var.
aborted 409 Eşzamanlı bir değişiklik önce uygulandı; yeniden okuyup tekrar deneyin.
resource_exhausted 429 Çok fazla istek: bekleme süresini artırarak yeniden deneyin.
unavailable 503 Chargeless ya da ödeme sağlayıcınız yanıt veremedi: aynı idempotency anahtarıyla yeniden deneyin.
deadline_exceeded 504 Çağrı çok uzun sürdü: aynı idempotency anahtarıyla yeniden deneyin.
internal 500 Hata bizden kaynaklanıyor: daha sonra aynı idempotency anahtarıyla yeniden deneyin.

Bir karar hiçbir zaman hata olarak dönmez. Politikanın reddettiği bir iade de başarılı bir çağrıdır; dönen işlemin durumu ACTION_STATUS_DENIED olur ve nedeni de yanıtta yer alır.

Idempotency ve Yeniden Denemeler

Bir şeyi değiştiren her çağrı, sizin seçtiğiniz bir anahtar alır. Aynı anahtarla yapılan yeniden deneme (retry) işlemi ikinci kez yapmaz, ilk sonucu döndürür (replayed: true):

  • ActionsService/Submit: idempotencyKey. Anahtar denemeyi değil, her zaman amacı (intent) adlandırmalıdır. İyi bir biçim backend:{your request id}:{action}:{target} şeklindedir; örneğin backend:ord_8812:refund:01a1aff4-53d6-7334-8e2d-9d3d35bfcff5. Aynı amaç için yapılan her yeniden denemede aynı anahtarı kullanın; anahtara asla zaman damgası ya da rastgele bir değer koymayın. Aynı anahtar başka bir tür ya da hedefle gelirse failed_precondition ile reddedilir.
  • RequestIntakeService/SubmitCustomerRequest: requestId, talebe sizin verdiğiniz kimlik.

unavailable, deadline_exceeded, internal ve resource_exhausted hatalarında aynı anahtarla, bekleme süresini artırarak (1, 2, 4, 8 sn …) yeniden deneyin; Retry-After başlığının belirttiği süreden önce asla denemeyin. İsteği gönderdikten sonra oluşan bir ağ hatası da aynı durumdur: isteğin ulaşıp ulaşmadığını bilemezsiniz, bu yüzden aynı anahtarla yeniden gönderin.

Limitler

Her çalışma alanı, API anahtarlarıyla toplamda (tüm anahtarlar birlikte) dakikada 600 çağrı yapabilir; kısa süreli yoğunluklarda (burst) art arda en fazla 100 çağrı gönderilebilir. Kota sürekli olarak, saniyede on çağrı hızında yenilenir. Kotayı aşan bir çağrı hiçbir etki yaratmaz ve Retry-After başlığıyla birlikte resource_exhausted (HTTP 429) yanıtı alır; bu başlık, bir sonraki çağrının kabul edilmesi için beklemeniz gereken süreyi tam saniye olarak verir. Bir anahtarın yaptığı her çağrı, yanıtı ne olursa olsun kotadan düşülür. Test çalışma alanlarının kotası ayrıdır.

Bu sınırdan önce, API sunucusu tek bir istemci IP adresinden dakikada en fazla 1.200 istek kabul eder ve fazlasını 429 ile yanıtlar. Listeler en fazla pageSize kadar öğe döndürür (her prosedürün kendi varsayılan ve azami değeri vardır); nextPageToken değerini değiştirmeden pageToken olarak geri gönderin ve içeriğini yorumlamayın (opak bir değerdir).

2. Oturum Açmış Bir Müşteri için İade veya İptal

Müşteri sitenizde oturum açmışsa sunucunuz, imzalı bir kimlik token'ıyla müşterinin kimliğine kefil olur ve ardından onun adına işlem yapar. Politika, widget'taki bir sohbette olduğu gibi karar verir.

Adım 1: Bir Kimlik Token'ı İmzalayın

Bu, widget'ın kullandığı token'ın aynısıdır: Widget İmza Anahtarı (srwgt_…, Ayarlar → Sohbet Widget'ı) ile imzalanan ve yalnızca sunucunuzda oluşturulan bir HS256 JWT.

Claim Değer
sub müşterinin ödeme sağlayıcınızdaki kimliği (Stripe cus_…, Paddle ctm_…, kendi sisteminizdeki kimlik)
tenant Çalışma alanı kimliğiniz (Workspace ID)
connection isteğe bağlı: müşterinin ait olduğu ödeme bağlantısı (Ayarlar → Entegrasyonlar); verilmezse ilk bağlantınız
email isteğe bağlı
iat, exp düzenlenme zamanı ve son geçerlilik zamanı; en fazla bir saat sonrası
js
import jwt from 'jsonwebtoken';

const token = jwt.sign(
  { sub: customer.stripeCustomerId, tenant: process.env.CHARGELESS_WORKSPACE_ID },
  process.env.CHARGELESS_WIDGET_SECRET, // srwgt_…
  { algorithm: 'HS256', expiresIn: '15m' },
);

Adım 2: Token'ı Doğrulayın

sh
curl -sS https://api.chargeless.io/sr.identity.v1.IdentityService/Verify \
  -H "Authorization: Bearer $CHARGELESS_API_KEY" -H "Content-Type: application/json" \
  -d '{"token": "eyJhbGciOiJIUzI1NiIs…"}'
json
{
  "customerId": "01a1aff4-5117-79a0-a966-68ed1a264ea1",
  "providerCustomerId": "cus_Q8x…",
  "method": "IDENTITY_METHOD_SIGNED_TOKEN",
  "connectionId": "01a1aff4-50ab-74ce-9c05-b142b747606c",
  "verifiedAt": "2026-11-06T09:30:00Z",
  "expiresAt": "2026-11-06T09:45:00Z"
}

customerId, müşterinin Chargeless defterindeki kimliğidir; sonraki adımlarda bu değeri kullanın. Doğrulanamayan ya da süresi dolmuş bir token için unauthenticated döner (mesaj, sorunun API anahtarınızda değil token'da olduğunu belirtir); defterde henüz kaydı olmayan bir müşteri için not_found döner.

Adım 3: Ödemelerini ve Aboneliklerini Sorgulayın

sh
curl -sS https://api.chargeless.io/sr.transactions.v1.TransactionsService/Lookup \
  -H "Authorization: Bearer $CHARGELESS_API_KEY" -H "Content-Type: application/json" \
  -d '{"customerIds": ["01a1aff4-5117-79a0-a966-68ed1a264ea1"], "limit": 20}'

Her ödeme kaydında (transaction) defterdeki id değeri, sağlayıcıdaki kimliği, amount, refunded, refundableRemainder ve state alanları, kartın markası ile son dört hanesi ve ödeme bağlantısı bulunur; her abonelikte ise id değeri, durumu ve planı. Yalnızca gönderdiğiniz müşterilerin kayıtları okunur.

Adım 4 (İsteğe Bağlı): Kararın Önizlemesini Alın

PolicyService/Evaluate, hiçbir şey kaydetmeden politikanın şu anda nasıl bir karar vereceğini döndürür:

sh
curl -sS https://api.chargeless.io/sr.policy.v1.PolicyService/Evaluate \
  -H "Authorization: Bearer $CHARGELESS_API_KEY" -H "Content-Type: application/json" \
  -d '{
        "actionType": "ACTION_TYPE_REFUND",
        "targetId": "01a1aff4-53d6-7334-8e2d-9d3d35bfcff5",
        "reasonCode": "duplicate",
        "source": "SOURCE_CHAT",
        "identityIds": ["01a1aff4-5117-79a0-a966-68ed1a264ea1"],
        "identityMethod": "IDENTITY_METHOD_SIGNED_TOKEN"
      }'

decision.outcome alanı OUTCOME_ALLOW, OUTCOME_DENY ya da OUTCOME_HANDOFF olur; yanında reasons (her biri bir kod ve bir açıklama cümlesi) ve amount döner. Önizleme bir taahhüt değildir: siz işlemi göndermeden önce kararın dayandığı bilgiler değişebilir ve gönderimde karar yeniden verilir.

Adım 5: İşlemi Gönderin

sh
curl -sS https://api.chargeless.io/sr.actions.v1.ActionsService/Submit \
  -H "Authorization: Bearer $CHARGELESS_API_KEY" -H "Content-Type: application/json" \
  -d '{
        "idempotencyKey": "backend:ord_8812:refund:01a1aff4-53d6-7334-8e2d-9d3d35bfcff5",
        "type": "ACTION_TYPE_REFUND",
        "targetId": "01a1aff4-53d6-7334-8e2d-9d3d35bfcff5",
        "reasonCode": "duplicate",
        "identity": {
          "customerId": "01a1aff4-5117-79a0-a966-68ed1a264ea1",
          "customerIds": ["01a1aff4-5117-79a0-a966-68ed1a264ea1"],
          "method": "IDENTITY_METHOD_SIGNED_TOKEN"
        },
        "requestedBy": "account-page",
        "waitSeconds": 5
      }'
  • type: ACTION_TYPE_REFUND (hedef: bir ödeme kaydı) ya da ACTION_TYPE_CANCEL_SUBSCRIPTION (hedef: bir abonelik). ACTION_TYPE_HANDOFF ise hedef almaz; bir handoffReason koduyla, para konusunda karar vermeden vakayı ekibinize devreder.
  • reasonCode: duplicate, forgot_to_cancel, unrecognized, not_as_described, service_issue ya da other. Politika kararını buna göre verebilir.
  • amount: isteğe bağlı; kısmi iade için, ödemenin para biriminde. Verilmezse iade edilebilir kalanın tamamı iade edilir.
  • requestedBy: talebin nereden geldiğini gösteren, sizin belirlediğiniz etiket; işlemde görünür. Zorunludur.
  • waitSeconds: yanıt vermeden önce sağlayıcının sonucunun ne kadar bekleneceği (varsayılan 5, en fazla 10).

Yanıt olarak işlemin kendisi döner:

json
{
  "action": {
    "id": "01a1aff5-427d-765f-a005-d2675fe290ab",
    "type": "ACTION_TYPE_REFUND",
    "status": "ACTION_STATUS_EXECUTED",
    "targetId": "01a1aff4-53d6-7334-8e2d-9d3d35bfcff5",
    "amount": {"amountMinor": "1900", "currency": "EUR"},
    "decision": {"outcome": "OUTCOME_ALLOW", "policyVersion": "v7", "reasons": [ … ]},
    "providerRef": "re_3Q…",
    "createdAt": "2026-11-06T09:31:02Z",
    "executedAt": "2026-11-06T09:31:03Z"
  },
  "replayed": false
}
status Anlamı
ACTION_STATUS_EXECUTED Sağlayıcıda gerçekleşti.
ACTION_STATUS_PENDING Onaylandı ve yürütülüyor ya da sağlayıcının sonucu bekleniyor.
ACTION_STATUS_DENIED Politika (ya da bir durdurma) reddetti; nedeni decision.reasons alanında.
ACTION_STATUS_HANDOFF Ekibinize devredildi; nedeni decision.reasons alanında.
ACTION_STATUS_FAILED Sağlayıcı yürütme sırasında reddetti; ayrıntısı failure alanında. İşlem ekibinize iletilir.

Adım 6: Bekleyen Bir İşlemi Takip Edin

İşlemi ActionsService/Get ({"actionId": "…"}) ile yeniden okuyun ya da, daha iyisi, action.executed ve action.failed webhook'larına abone olun (webhooks.md). Bazı sağlayıcılar iadeyi diğerlerinden daha geç onaylar (Paddle iadeleri inceler; Adyen ve Ecommpay bildirimle onaylar); 24 saat içinde sonuç gelmezse işlem ekibinize devredilir.

3. Kendi Destek Formunuzdan Gelen İstekler

Widget yerine kendi formunuzu kullanıyorsanız her isteği RequestIntakeService/SubmitCustomerRequest prosedürüne gönderin. Prosedür bir talep (ticket) açar ve politika isteği hemen karara bağlar; müşteri süreci kendi talep sayfasından izler.

sh
curl -sS https://api.chargeless.io/sr.tickets.v1.RequestIntakeService/SubmitCustomerRequest \
  -H "Authorization: Bearer $CHARGELESS_API_KEY" -H "Content-Type: application/json" \
  -d '{
        "requestId": "form-20261106-0042",
        "action": "ACTION_TYPE_REFUND",
        "targetId": "ch_3Q8x…",
        "reasonCode": "duplicate",
        "message": "I was charged twice for my order.",
        "locale": "en",
        "requesterName": "Kim Okafor",
        "email": "[email protected]"
      }'
  • requestId: isteğe sizin verdiğiniz kimlik; [A-Za-z0-9_-] kümesinden 1–128 karakter. Idempotency anahtarı da budur: yeniden deneme, aynı talebi replayed: true ve isteğin güncel sonucuyla döndürür; bu yüzden durumu bu kimlikle yoklayabilirsiniz (polling).
  • action: ACTION_TYPE_REFUND ya da ACTION_TYPE_CANCEL_SUBSCRIPTION.
  • targetId: bir defter kimliği ya da ödemenin veya aboneliğin sağlayıcınızdaki kimliği (Stripe'ta ch_… ya da sub_…); sağlayıcı kimliği verdiğinizde connectionId bu kimliğin ait olduğu ödeme bağlantısını belirtir (boş bırakılırsa ilk bağlantınız).
  • Tam olarak bir kimlik kanıtı:
    • identityToken: oturum açmış müşteri için 2. bölümdeki imzalı token. İstek o müşteriyle eşleştirilir ve hemen karara bağlanır.
    • email: formda girilen adres. Elle yazılmış bir adres hiçbir şey kanıtlamaz; bu yüzden istek doğrulanmamış kabul edilerek karara bağlanır (CUSTOMER_REQUEST_OUTCOME_IDENTITY_REQUIRED) ve bu adrese tek kullanımlık bağlantı içeren bir e-posta gönderilir. Adresin sahibi, adresin kendisine ait olduğunu kanıtlayıp isteği talep sayfasında onaylar; istek ancak bundan sonra yeniden karara bağlanır.

Yanıt, talebi ve isteğin hangi aşamada olduğunu belirtir:

json
{
  "ticketId": "01a1b00b-…",
  "ticketNumber": "1042",
  "pageUrl": "https://acme.help.chargeless.io/t/9fK2…",
  "outcome": "CUSTOMER_REQUEST_OUTCOME_IDENTITY_REQUIRED",
  "reasonCode": "identity_required",
  "actionId": "01a1b00b-…",
  "replayed": false
}

outcome değeri EXECUTED, PENDING, DENIED, HANDOFF ya da IDENTITY_REQUIRED olur (her birinin başında CUSTOMER_REQUEST_OUTCOME_ öneki bulunur). Müşteriye pageUrl adresini gösterin: bu adres talebi tanımlar ama tek başına hiçbir yetki vermez, çünkü sayfa önce kimlik kanıtı ister. Onaydan sonra istek yeniden karara bağlandığında customer_request.decided webhook'u sizi bilgilendirir.

4. Verileri Kendi Sistemlerinize Aktarmak

Prosedür Ne döndürür
sr.tenant.v1.TenantService/GetTenant Çalışma alanınız: durumu (canlı, kurulumda, askıya alınmış), acil durdurma, yardım sitesi
sr.policy.v1.PolicyService/GetPublished Yayımlanmış politika belgesi (base64) ve sürümü
sr.policy.v1.PolicyService/ListVersions, GetVersion Politikanın sürüm geçmişi ve önceki herhangi bir sürüm
sr.policy.v1.PolicyService/Evaluate Bir karar önizlemesi (2. bölüm, 4. adım)
sr.cases.v1.CasesService/ListActions Tüm işlemler, en yeniden eskiye; zamana, türe, duruma ve kaynağa göre filtrelenebilir
sr.cases.v1.CasesService/ListCases, GetCase Vakalar (sohbet, talep, dolandırıcılık uyarısı, itiraz) ve tek bir vakanın zaman çizelgesi ile karar olguları
sr.cases.v1.CasesService/ListRefunds İadeler: Chargeless'ın yaptıkları, sağlayıcıda ya da kendi sisteminizde yapılanlar; para birimi başına toplamlarla
sr.cases.v1.CasesService/ListDisputes İtirazlar ve sorgular, son tarihleriyle
sr.cases.v1.CasesService/ListFraudWarnings Erken dolandırıcılık uyarıları ve her biri için yapılanlar
sr.cases.v1.CasesService/ListSubscriptions Tüm ödeme bağlantılarınızdaki abonelikler
sr.cases.v1.CasesService/ListProviderCalls Chargeless'ın kendi ödeme sisteminize yaptığı çağrılar (işletmenin barındırdığı bağlantılar)
sr.cases.v1.CasesService/GetProviderHealth Kendi ödeme sisteminizin sağlık durumu, izleme için
sr.identity.v1.IdentityService/LookupCustomer Bir e-posta adresinin ait olduğu müşteriler, ödeme bağlantısı bazında
sr.actions.v1.ActionsService/Get Tek bir işlem

Listeler bir zaman aralığına (from, to) ve kendi alanlarına göre filtrelenir; pageSize ve pageToken ile sayfalanır. Her listenin sayfa boyutunu ve zaman aralığının zorunlu olup olmadığını API başvurusu belirtir. Tüm alanlar openapi/backend-api/v1.yaml dosyasında yer alır.

5. Tipli Bir İstemci

OpenAPI belgesi tüm OpenAPI araçlarıyla kullanılabilir. Alan tiplerini birebir koruyan tipli bir istemci için istemciyi proto dosyalarından, Buf ve dilinize uygun Connect kod üreticisiyle (Go, TypeScript, Kotlin, Swift, Python, Dart) üretin:

yaml
# buf.gen.yaml
version: v2
plugins:
  - remote: buf.build/connectrpc/go
    out: gen
    opt: paths=source_relative
  - remote: buf.build/protocolbuffers/go
    out: gen
    opt: paths=source_relative
go
client := actionsv1connect.NewActionsServiceClient(http.DefaultClient, "https://api.chargeless.io")
req := connect.NewRequest(&actionsv1.SubmitRequest{ /* … */ })
req.Header().Set("Authorization", "Bearer "+os.Getenv("CHARGELESS_API_KEY"))
res, err := client.Submit(ctx, req)

6. Sürümler ve Değişiklikler

Her paketin bir sürümü vardır (sr.actions.v1). v1 içinde alanlar ve prosedürler yalnızca eklenir; bir alan asla yeniden adlandırılmaz, tipi değiştirilmez ya da başka amaçla yeniden kullanılmaz. Mevcut bir entegrasyonu bozacak bir değişiklik, v1'in yanında v2 olarak yayımlanır. Tüm değişiklikler CHANGELOG.md dosyasında yer alır. Tanımadığınız alanları yok sayın; bir alan sıralı olduğunu belirtmedikçe alanların ya da liste öğelerinin sırasına güvenmeyin.