Cost+Docs

Java / Kotlin

Offizielles Kotlin/Java SDK für das Cost+ Zahlungsgateway

Offizielles Kotlin SDK für das Cost+ Zahlungsgateway, vollständig interoperabel mit Java. Vereinfacht den HPP (Hosted Payment Page) Weiterleitungsablauf, die HMAC-Payload-Signierung und die Webhook-Verifizierung.

Funktionen

  • Kotlin-first, Java-kompatibel — Data Classes, Coroutines, Null Safety; vollständig aus Java nutzbar
  • kotlinx.serialization — keine Gson/Jackson-Abhängigkeit; automatisches snake_case/camelCase-Mapping
  • HMAC-SHA256-Signaturgenerierung und zeitkonstante Verifizierung
  • Webhook-Parsing + API-basierte Bestellungsverifizierung
  • Suspend-Funktionen für nicht-blockierende IO über Kotlin Coroutines
  • Injizierbarer HttpClient für einfaches Testen mit Mock-Transports
  • Zielplattform Java 17+

Voraussetzungen

Installation

Gradle (Kotlin DSL)

dependencies {
    implementation("io.nopayn:nopayn-sdk:1.0.0")
}

Gradle (Groovy)

dependencies {
    implementation 'io.nopayn:nopayn-sdk:1.0.0'
}

Maven

<dependency>
    <groupId>io.nopayn</groupId>
    <artifactId>nopayn-sdk</artifactId>
    <version>1.0.0</version>
</dependency>

Schnellstart (Kotlin)

1. Client initialisieren

import io.nopayn.*
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    val nopayn = NoPaynClient(
        NoPaynConfig(
            apiKey = "your-api-key",
            merchantId = "your-project",
        )
    )
}

2. Zahlung erstellen und zur HPP weiterleiten

val result = nopayn.generatePaymentUrl(
    CreateOrderParams(
        amount = 1295,            // €12.95 in cents
        currency = "EUR",
        merchantOrderId = "ORDER-001",
        description = "Premium Widget",
        returnUrl = "https://shop.example.com/success",
        failureUrl = "https://shop.example.com/failure",
        webhookUrl = "https://shop.example.com/webhook",
        locale = "en-GB",
        expirationPeriod = "PT30M",
    )
)

println(result.orderUrl)    // HPP URL
println(result.paymentUrl)  // Direct payment method URL
println(result.signature)   // HMAC-SHA256 signature

3. Webhook verarbeiten

// In your HTTP handler (Ktor, Spring, etc.)
val rawBody: String = request.body()
val verified = nopayn.verifyWebhook(rawBody)

println(verified.order.status)  // "completed", "cancelled", etc.
println(verified.isFinal)       // true when the order won't change

if (verified.order.status == "completed") {
    // Fulfil the order
}

Schnellstart (Java)

import io.nopayn.*;
import kotlinx.coroutines.BuildersKt;
import kotlinx.coroutines.Dispatchers;

public class Example {
    public static void main(String[] args) throws Exception {
        NoPaynClient client = new NoPaynClient(
            new NoPaynConfig("your-api-key", "your-project", "https://api.nopayn.co.uk")
        );

        Order order = BuildersKt.runBlocking(
            Dispatchers.getIO(),
            (scope, continuation) -> client.createOrder(
                new CreateOrderParams(
                    1295, "EUR", "ORDER-001", "Premium Widget",
                    "https://shop.example.com/success",
                    "https://shop.example.com/failure",
                    "https://shop.example.com/webhook",
                    "en-GB", null, "PT30M"
                ),
                continuation
            )
        );

        System.out.println("Order ID: " + order.getId());
        System.out.println("Order URL: " + order.getOrderUrl());

        // Signature utilities work synchronously
        String sig = client.generateSignature(1295, "EUR", order.getId());
        boolean valid = client.verifySignature(1295, "EUR", order.getId(), sig);
    }
}

API-Referenz

NoPaynClient(config, httpClient?)

ParameterTypErforderlichStandard
config.apiKeyStringJa
config.merchantIdStringJa
config.baseUrlStringNeinhttps://api.nopayn.co.uk
httpClientjava.net.http.HttpClientNeinStandard-Client

client.createOrder(params): Order (suspend)

Erstellt eine Bestellung über POST /v1/orders/.

ParameterTypErforderlichBeschreibung
amountIntJaBetrag in kleinster Währungseinheit (Cent)
currencyStringJaISO 4217 Code (EUR, GBP, USD, NOK, SEK)
merchantOrderIdString?NeinIhre interne Bestellreferenz
descriptionString?NeinBestellbeschreibung
returnUrlString?NeinWeiterleitung nach erfolgreicher Zahlung
failureUrlString?NeinWeiterleitung bei Abbruch/Ablauf/Fehler
webhookUrlString?NeinAsynchrone Statusänderungs-Benachrichtigungen
localeString?NeinHPP-Sprache (en-GB, de-DE, nl-NL usw.)
paymentMethodsList<String>?NeinHPP-Methoden filtern
expirationPeriodString?NeinISO 8601 Dauer (PT30M)

Verfügbare Zahlungsmethoden: credit-card, apple-pay, google-pay, vipps-mobilepay

client.getOrder(orderId): Order (suspend)

Ruft Bestellungsdetails über GET /v1/orders/{id}/ ab.

client.createRefund(orderId, amount, description?): Refund (suspend)

Stellt eine vollständige oder teilweise Erstattung über POST /v1/orders/{id}/refunds/ aus.

client.generatePaymentUrl(params): PaymentUrlResult (suspend)

Komfortmethode, die eine Bestellung erstellt und zurückgibt:

PaymentUrlResult(
    orderId: String,     // NoPayn order UUID
    orderUrl: String,    // HPP URL
    paymentUrl: String?, // Direct payment URL (first transaction)
    signature: String,   // HMAC-SHA256 of amount:currency:orderId
    order: Order,        // Full order object
)

client.generateSignature(amount, currency, orderId): String

Generiert eine HMAC-SHA256-Hex-Signatur. Die kanonische Nachricht ist $amount:$currency:$orderId, signiert mit dem API-Schlüssel.

client.verifySignature(amount, currency, orderId, signature): Boolean

Zeitkonstante Verifizierung einer HMAC-SHA256-Signatur.

client.verifyWebhook(rawBody): VerifiedWebhook (suspend)

Parst den Webhook-Body und ruft dann GET /v1/orders/{id}/ auf, um den tatsächlichen Status zu verifizieren.

Eigenständige HMAC-Hilfsfunktionen

import io.nopayn.NoPaynSignature

val sig = NoPaynSignature.generate("your-api-key", 1295, "EUR", "order-uuid")
val ok  = NoPaynSignature.verify("your-api-key", 1295, "EUR", "order-uuid", sig)

Aus Java:

String sig = NoPaynSignature.generate("your-api-key", 1295, "EUR", "order-uuid");
boolean ok = NoPaynSignature.verify("your-api-key", 1295, "EUR", "order-uuid", sig);

Fehlerbehandlung

import io.nopayn.*

try {
    nopayn.createOrder(CreateOrderParams(amount = 100, currency = "EUR"))
} catch (e: ApiException) {
    println(e.statusCode)  // 401, 400, etc.
    println(e.errorBody)   // Raw API error response
} catch (e: NoPaynException) {
    println(e.message)     // Network or parsing error
}

Bestellungsstatus

StatusEndgültig?Beschreibung
newNeinBestellung erstellt
processingNeinZahlung in Bearbeitung
completedJaZahlung erfolgreich — Ware liefern
cancelledJaZahlung vom Kunden storniert
expiredJaZahlungslink abgelaufen
errorJaTechnischer Fehler

Webhook Best Practices

  1. Immer über die API verifizieren — der Webhook-Payload enthält nur die Bestell-ID, niemals den Status. Die verifyWebhook()-Methode des SDK erledigt dies automatisch.
  2. HTTP 200 zurückgeben, um den Empfang zu bestätigen. Jeder andere Code löst bis zu 10 Wiederholungsversuche aus (im 2-Minuten-Abstand).
  3. Backup-Poller implementieren — für Bestellungen, die älter als 10 Minuten sind und noch keinen Endstatus erreicht haben, getOrder() als Sicherheitsnetz abfragen.
  4. Idempotent sein — Sie können denselben Webhook mehrfach erhalten.

Testkarten

Verwenden Sie diese Karten im Cost+ Testmodus (Sandbox-Website):

KarteNummerHinweise
Visa (Erfolg)4111 1111 1111 1111Beliebiger CVV
Mastercard (Erfolg)5544 3300 0003 7Beliebiger CVV
Visa (abgelehnt)4111 1111 1111 1105Do Not Honor
Visa (unzureichendes Guthaben)4111 1111 1111 1151Insufficient Funds

Verwenden Sie ein beliebiges zukünftiges Ablaufdatum und eine beliebige 3-stellige CVC.

Demo-App

Eine Docker-basierte Demo-App (Ktor) ist im GitHub-Repository enthalten, um den vollständigen Zahlungsablauf zu testen.

Support

Brauchen Sie Hilfe? Kontaktieren Sie unser Support-Team unter support@costplus.io.

On this page