vellTRDocs

Kvell Go SDK

v1.1.0Requirements: Go 1.21+

Install

Shell
go get github.com/kvell/kvell-go

Initialize

Go
package main

import (
	"os"

	"github.com/kvell/kvell-go"
)

func newKvellClient() *kvell.Client {
	return kvell.NewClient(kvell.Config{
		APIKey:      os.Getenv("KVELL_API_KEY"),
		SecretKey:   os.Getenv("KVELL_SECRET_KEY"),
		Environment: "sandbox", // switch to "production" when you go live
	})
}

Quickstart

Go
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/kvell/kvell-go"
)

func main() {
	client := kvell.NewClient(kvell.Config{
		APIKey:      os.Getenv("KVELL_API_KEY"),
		SecretKey:   os.Getenv("KVELL_SECRET_KEY"),
		Environment: "sandbox",
	})

	// Amounts are always integers in kuruş (1/100 TRY) — 15000 = 150.00 TRY
	session, err := client.PaymentSessions.Create(context.Background(), kvell.CreateSessionParams{
		TransactionID: "ORDER-2026-001",
		Amount:        15000,
		Currency:      "TRY",
		Description:   "Order #1234",
		ReturnURL:     "https://merchant.example.com/return",
	})
	if err != nil {
		log.Fatalf("create session: %v", err)
	}

	fmt.Println("Redirect the buyer to:", session.CheckoutURL)
}

Error handling

Go
package main

import (
	"context"
	"errors"
	"log"
	"os"

	"github.com/kvell/kvell-go"
)

func main() {
	client := kvell.NewClient(kvell.Config{
		APIKey:      os.Getenv("KVELL_API_KEY"),
		SecretKey:   os.Getenv("KVELL_SECRET_KEY"),
		Environment: "sandbox",
	})

	payment, err := client.Payments.Charge(context.Background(), kvell.ChargeParams{
		TransactionID: "ORDER-2026-001",
		Amount:        15000, // kuruş
		Currency:      "TRY",
		CardToken:     "tok_9f8e7d6c5b4a",
	})
	if err != nil {
		var kerr *kvell.Error
		if errors.As(err, &kerr) {
			switch kerr.Code {
			case "KVELL-PAY-4001":
				log.Fatalf("card declined (requestId=%s)", kerr.RequestID)
			case "KVELL-GW-1002":
				log.Fatalf("signature invalid, check your secret key (requestId=%s)", kerr.RequestID)
			default:
				log.Fatalf("kvell error %s (requestId=%s)", kerr.Code, kerr.RequestID)
			}
		}
		log.Fatalf("charge failed: %v", err)
	}

	log.Printf("captured payment %s", payment.PaymentID)
}

Verify webhooks

Go
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"io"
	"net/http"
	"os"

	"github.com/kvell/kvell-go"
)

var seenEventIDs = map[string]bool{} // swap for Redis/DB in production

func kvellWebhookHandler(w http.ResponseWriter, r *http.Request) {
	rawBody, _ := io.ReadAll(r.Body) // raw bytes, never the parsed JSON
	signature := r.Header.Get("X-Kvell-Signature")
	eventID := r.Header.Get("X-Kvell-Event-Id")

	mac := hmac.New(sha256.New, []byte(os.Getenv("KVELL_WEBHOOK_SECRET")))
	mac.Write(rawBody)
	expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
	if !hmac.Equal([]byte(signature), []byte(expected)) {
		http.Error(w, "invalid signature", http.StatusUnauthorized)
		return
	}
	if seenEventIDs[eventID] {
		w.WriteHeader(http.StatusOK) // already processed, ack and stop
		return
	}
	seenEventIDs[eventID] = true

	var event kvell.Event
	json.Unmarshal(rawBody, &event)
	switch event.EventType {
	case "payment.captured":
		// Fulfil the order asynchronously; respond fast below
	}
	w.WriteHeader(http.StatusOK)
}