Cost+Docs

Java / Kotlin

Officielt Kotlin/Java SDK til Cost+ betalingsgateway

Officielt Kotlin SDK til Cost+ betalingsgateway, fuldt interoperabelt med Java. Forenkler HPP (Hosted Payment Page) redirect-flowet, HMAC payload-signering og webhook-verificering.

Funktioner

  • Kotlin-first, Java-venligt — data classes, coroutines, null safety; fuldt anvendeligt fra Java
  • kotlinx.serialization — ingen Gson/Jackson-afhængighed; automatisk snake_case/camelCase-mapping
  • HMAC-SHA256 signaturgenerering og tidskonstant verificering
  • Webhook-parsing + API-baseret ordreverificering
  • Suspend functions til non-blocking IO via Kotlin coroutines
  • Injicerbar HttpClient til nem test med mock transports
  • Targeterer Java 17+

Krav

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>

Hurtigstart (Kotlin)

1. Initialiser klienten

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

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

2. Opret en betaling og omdiriger til HPP'en

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. Håndter webhooken

// 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
}

Hurtigstart (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-reference

NoPaynClient(config, httpClient?)

ParameterTypePåkrævetStandard
config.apiKeyStringJa
config.merchantIdStringJa
config.baseUrlStringNejhttps://api.nopayn.co.uk
httpClientjava.net.http.HttpClientNejStandardklient

client.createOrder(params): Order (suspend)

Opretter en ordre via POST /v1/orders/.

ParameterTypePåkrævetBeskrivelse
amountIntJaBeløb i mindste valutaenhed (øre/cent)
currencyStringJaISO 4217-kode (EUR, GBP, USD, NOK, SEK)
merchantOrderIdString?NejDin interne ordrereference
descriptionString?NejOrdrebeskrivelse
returnUrlString?NejOmdirigering efter vellykket betaling
failureUrlString?NejOmdirigering ved annullering/udløb/fejl
webhookUrlString?NejAsynkrone statusændringsnotifikationer
localeString?NejHPP-sprog (en-GB, de-DE, nl-NL osv.)
paymentMethodsList<String>?NejFiltrer HPP-metoder
expirationPeriodString?NejISO 8601-varighed (PT30M)

Tilgængelige betalingsmetoder: credit-card, apple-pay, google-pay, vipps-mobilepay

client.getOrder(orderId): Order (suspend)

Henter ordredetaljer via GET /v1/orders/{id}/.

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

Udsteder en fuld eller delvis refusion via POST /v1/orders/{id}/refunds/.

client.generatePaymentUrl(params): PaymentUrlResult (suspend)

Convenience-metode der opretter en ordre og returnerer:

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

Genererer en HMAC-SHA256 hex-signatur. Den kanoniske besked er $amount:$currency:$orderId, signeret med API-nøglen.

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

Tidskonstant verificering af en HMAC-SHA256-signatur.

client.verifyWebhook(rawBody): VerifiedWebhook (suspend)

Parser webhook-kroppen og kalder derefter GET /v1/orders/{id}/ for at verificere den faktiske status.

Selvstændige HMAC-hjælpefunktioner

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)

Fra Java:

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

Fejlhåndtering

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
}

Ordrestatusser

StatusEndelig?Beskrivelse
newNejOrdre oprettet
processingNejBetaling i gang
completedJaBetaling vellykket — lever varerne
cancelledJaBetaling annulleret af kunden
expiredJaBetalingslink udløbet
errorJaTeknisk fejl

Webhook best practices

  1. Verificer altid via API'et — webhook-payloaden indeholder kun ordre-ID'et, aldrig status. SDK'ets verifyWebhook() gør dette automatisk.
  2. Returner HTTP 200 for at bekræfte modtagelsen. Enhver anden kode udløser op til 10 genforsøg (2 minutters mellemrum).
  3. Implementer en backup-poller — for ordrer ældre end 10 minutter, der ikke har nået en endelig status, poll getOrder() som sikkerhedsnet.
  4. Vær idempotent — du kan modtage den samme webhook flere gange.

Testkort

Brug disse kort i Cost+ testtilstand (sandbox-website):

KortNummerNoter
Visa (succes)4111 1111 1111 1111Vilkårlig CVV
Mastercard (succes)5544 3300 0003 7Vilkårlig CVV
Visa (afvist)4111 1111 1111 1105Do Not Honor
Visa (utilstrækkelig saldo)4111 1111 1111 1151Insufficient Funds

Brug en vilkårlig fremtidig udløbsdato og en vilkårlig 3-cifret CVC.

Demo-app

En Docker-baseret demo-app (Ktor) er inkluderet i GitHub-repositoriet til test af det fulde betalingsflow.

Support

Brug for hjælp? Kontakt vores supportteam på support@costplus.io.

On this page