vellTRDocs
SDKsJava

Kvell Java SDK

v1.2.0Requirements: Java 11+

Install

Shell
implementation "group.kvell:kvell-java:1.2.0"

Initialize

Java
import group.kvell.KvellClient;

KvellClient kvell = KvellClient.builder()
    .apiKey(System.getenv("KVELL_API_KEY"))
    .secretKey(System.getenv("KVELL_SECRET_KEY"))
    .environment("sandbox") // switch to "production" when you go live
    .build();

Quickstart

Java
import group.kvell.KvellClient;
import group.kvell.model.CreateSessionParams;
import group.kvell.model.PaymentSession;

public class CreateCheckout {
    public static void main(String[] args) {
        KvellClient kvell = KvellClient.builder()
            .apiKey(System.getenv("KVELL_API_KEY"))
            .secretKey(System.getenv("KVELL_SECRET_KEY"))
            .environment("sandbox")
            .build();

        // Amounts are always integers in kuruş (1/100 TRY) — 15000 = 150.00 TRY
        PaymentSession session = kvell.paymentSessions().create(CreateSessionParams.builder()
            .transactionId("ORDER-2026-001")
            .amount(15000)
            .currency("TRY")
            .description("Order #1234")
            .returnUrl("https://merchant.example.com/return")
            .build());

        System.out.println("Redirect the buyer to: " + session.getCheckoutUrl());
    }
}

Error handling

Java
import group.kvell.KvellClient;
import group.kvell.KvellError;
import group.kvell.model.ChargeParams;
import group.kvell.model.Payment;

public class ChargeCard {
    public static void main(String[] args) {
        KvellClient kvell = KvellClient.builder()
            .apiKey(System.getenv("KVELL_API_KEY"))
            .secretKey(System.getenv("KVELL_SECRET_KEY"))
            .environment("sandbox")
            .build();

        try {
            Payment payment = kvell.payments().charge(ChargeParams.builder()
                .transactionId("ORDER-2026-001")
                .amount(15000) // kuruş
                .currency("TRY")
                .cardToken("tok_9f8e7d6c5b4a")
                .build());
            System.out.println("Captured payment " + payment.getPaymentId());
        } catch (KvellError err) {
            switch (err.getCode()) {
                case "KVELL-PAY-4001":
                    System.err.println("Card declined (requestId=" + err.getRequestId() + ")");
                    break;
                case "KVELL-GW-1002":
                    System.err.println("Signature invalid, check your secret key (requestId=" + err.getRequestId() + ")");
                    break;
                default:
                    System.err.println("Kvell error " + err.getCode() + " (requestId=" + err.getRequestId() + ")");
            }
            throw err;
        }
    }
}

Verify webhooks

Java
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@RestController
public class KvellWebhookController {
    // swap for Redis/DB in production
    private final Set<String> seenEventIds = ConcurrentHashMap.newKeySet();

    @PostMapping(value = "/webhooks/kvell", consumes = "application/json")
    public ResponseEntity<String> handle(@RequestBody byte[] rawBody,
            @RequestHeader("X-Kvell-Signature") String signature,
            @RequestHeader("X-Kvell-Event-Id") String eventId) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(System.getenv("KVELL_WEBHOOK_SECRET").getBytes(), "HmacSHA256"));
        StringBuilder hex = new StringBuilder("sha256=");
        for (byte b : mac.doFinal(rawBody)) hex.append(String.format("%02x", b & 0xff));

        if (!MessageDigest.isEqual(signature.getBytes(), hex.toString().getBytes())) {
            return ResponseEntity.status(401).body("invalid signature");
        }
        if (!seenEventIds.add(eventId)) {
            return ResponseEntity.ok("duplicate");
        }

        String eventType = KvellEvent.parse(rawBody).getEventType();
        switch (eventType) {
            case "payment.captured":
                // Fulfil the order asynchronously; respond fast below
                break;
            default:
                break;
        }
        return ResponseEntity.ok("ok");
    }
}