Payments
Accept card payments and TR QR. Create checkout sessions, charge tokenized cards (3DS 2.0), preauth/capture/void, and refund.
/v1/payments/sessionsCoreCreate a hosted-checkout session. The session holds the amount, description, and redirect URLs; the buyer completes the card (or TR QR) flow on the Kvell hosted page. Set mode="qr" to mint a BKM/TCMB TR QR payment instead of a card checkout.
Request Parameters
| Name | Type | Required | Description |
|---|---|---|---|
transactionId | string | Required | Unique merchant transaction id (idempotency fence, unique per merchant) |
amount | integer | Optional | Amount in kuruş (1/100 TRY). >=100 for mode="payment"/"qr"; omit for mode="card_update_only" |
currency | string | Required | ISO 4217, always "TRY" in Phase 1 |
description | string | Optional | Transaction description shown on the checkout page |
returnUrl | string | Required | Redirect URL after the buyer finishes (success or failure) |
callbackUrl | string | Optional | Override the store default webhook URL for this payment |
installmentEnabled | boolean | Optional | Show the installment picker on the hosted page |
customerId | string | Optional | Bind the session to a saved customer (enables save-card) |
mode | string | Optional | "payment" (default) | "card_update_only" | "qr" |
splits | array | Optional | Marketplace split config [{submerchantId, amountMinor}] — payment mode only |
{
"transactionId": "ORDER-2026-001",
"amount": 15000,
"currency": "TRY",
"description": "Order #1234",
"returnUrl": "https://merchant.example.com/return"
}{
"sessionId": "3f1c9a2e-6b4d-4e8a-9c1f-2a7b8c9d0e1f",
"checkoutUrl": "https://pay.kvell.group/s/3f1c9a2e-6b4d-4e8a-9c1f-2a7b8c9d0e1f",
"expiresAt": "2026-04-13T10:30:00Z",
"merchantId": "mrc_8a1b2c3d4e5f",
"amount": 15000,
"currency": "TRY",
"status": "active"
}/v1/payments/cardCoreCharge a card using a vault token (never a raw PAN — tokenize first via POST /v1/cards/tokens). Handles the 3DS 2.0 challenge dance. Set capture=false for a preauthorization (Slice 9): the row lands at status="authorized" with no ledger entries until a follow-up /capture or /void.
Request Parameters
| Name | Type | Required | Description |
|---|---|---|---|
transactionId | string | Required | Session transaction id (idempotency fence) |
amount | integer | Required | Amount in kuruş |
currency | string | Required | Always "TRY" |
cardToken | string | Required | Vault token (tok_…) from POST /v1/cards/tokens |
installmentCount | integer | Optional | Installment count 1..12 (re-checked against installment-service) |
threeDSecure | boolean | Optional | Force 3DS (default true) |
customerId | string | Optional | Save-card is honored only for a session-bound customer |
saveCard | boolean | Optional | Attach the card to the customer after capture |
capture | boolean | Optional | Auto-capture (default true); false = preauth |
{
"transactionId": "ORDER-2026-001",
"amount": 15000,
"currency": "TRY",
"cardToken": "tok_9f8e7d6c5b4a",
"installmentCount": 3
}{
"paymentId": "pay_1a2b3c4d5e6f",
"status": "captured",
"amount": 15000,
"currency": "TRY",
"commission": 449,
"netAmount": 14551,
"cardMask": "415565******4321",
"cardBrand": "visa",
"cardType": "credit",
"installmentCount": 3,
"threeDSecure": true,
"authCode": "123456",
"createdAt": "2026-04-13T10:00:00Z",
"completedAt": "2026-04-13T10:00:02Z"
}/v1/payments/{id}/3ds-callbackOptionalComplete a 3DS challenge. The hosted checkout posts the ACS pares + the correlationId returned from the card charge. Idempotent — a duplicate submit returns the winner's row byte-for-byte.
Request Parameters
| Name | Type | Required | Description |
|---|---|---|---|
pares | string | Required | Signed ACS assertion from the 3DS challenge |
correlationId | string | Required | Value round-tripped from the card charge response |
{
"pares": "eyJjaGFsbGVuZ2VJZCI6Ii4uLiJ9.9a8b7c6d",
"correlationId": "c0rr-3f1c-9a2e-6b4d"
}{
"id": "pay_1a2b3c4d5e6f",
"status": "captured",
"amount": 15000,
"currency": "TRY",
"commission": 449,
"netAmount": 14551,
"authCode": "123456",
"completedAt": "2026-04-13T10:00:05Z"
}/v1/payments/{id}/captureRecommendedCapture a preauthorized payment (full amount only — partial/multi-capture is Phase 2). Idempotent against an already-captured row.
{}{
"id": "pay_1a2b3c4d5e6f",
"status": "captured",
"amount": 15000,
"currency": "TRY",
"commission": 449,
"netAmount": 14551,
"refundableAmount": 15000,
"completedAt": "2026-04-13T10:05:00Z"
}/v1/payments/{id}/voidRecommendedRelease an uncaptured authorization. No ledger entries are posted (no money moved on Kvell's books). Idempotent against an already-voided row.
Request Parameters
| Name | Type | Required | Description |
|---|---|---|---|
reason | string | Optional | Free text (≤500 chars), surfaced on the payment.voided event |
{
"reason": "Order abandoned"
}{
"id": "pay_1a2b3c4d5e6f",
"status": "voided",
"amount": 15000,
"currency": "TRY"
}/v1/payments/{id}/refundCoreRefund a captured payment fully or partially. 200 when the refund settled synchronously; 202 when it is in-flight (the refund-reconciler completes it — do not mint a fresh Idempotency-Key on 202). Supports an optional Idempotency-Key header.
Request Parameters
| Name | Type | Required | Description |
|---|---|---|---|
amount | integer | Optional | Partial refund amount in kuruş (<= refundableAmount). Omit for a full refund. |
reason | string | Optional | Refund reason (truncated at 500 chars) |
{
"amount": 5000,
"reason": "Customer request"
}{
"paymentId": "pay_1a2b3c4d5e6f",
"status": "captured",
"refundAmount": 5000,
"refundableAmount": 10000,
"lastRefund": {
"refundId": "rfn_7c8d9e0f1a2b",
"status": "completed",
"amount": 5000,
"bankRefundId": "rfn_mock_44182",
"createdAt": "2026-04-13T14:00:00Z",
"completedAt": "2026-04-13T14:00:01Z"
}
}/v1/payments/{id}CoreRetrieve the full payment object.
{
"id": "pay_1a2b3c4d5e6f",
"merchantId": "mrc_8a1b2c3d4e5f",
"transactionId": "ORDER-2026-001",
"status": "captured",
"amount": 15000,
"currency": "TRY",
"commission": 449,
"netAmount": 14551,
"cardMask": "415565******4321",
"cardBrand": "visa",
"cardType": "credit",
"bin": "415565",
"installmentCount": 3,
"threeDSecure": true,
"refundAmount": 0,
"refundableAmount": 15000,
"createdAt": "2026-04-13T10:00:00Z",
"completedAt": "2026-04-13T10:00:02Z"
}/v1/payments/{id}/public-statusRecommendedBuyer-safe status poll — no auth (the paymentId UUID is the bearer). Used by the QR buyer page and the card-flow success poll. Returns only a narrow field set (never PAN, fee, merchant id, or auth code).
{
"paymentId": "pay_1a2b3c4d5e6f",
"status": "captured"
}Category Summary
Total Endpoints
8
Base Domain
api.pay.kvell.group