Klix
TypeScript SDK and NestJS adapter for Klix API.
Targets Node.js 20+. Ships dual ESM/CommonJS builds and a first-class NestJS subpath export.
Install
npm install @biggora/klix
NestJS apps also need peer deps:
npm install @nestjs/common @nestjs/core reflect-metadata rxjs
Quick Start: Checkout
Create a purchase, redirect the customer to checkout_url, then confirm the final state with a success callback or webhook before fulfilling the order.
Features
- Full current REST surface from Klix OpenAPI schema
- Typed resources for purchases, clients, billing, webhooks, statements, balance, payment methods
- Built-in auth, timeout handling, error normalization, and pagination helpers
paymentMethods.list()server-side cache enabled by default for 60 seconds- Success callback signature verification through
/public_key/ - Pure webhook signature verification helper
- NestJS
KlixModule.forRoot()andKlixModule.forRootAsync()
Plain Node.js
import { createKlixClient } from '@biggora/klix';
const klix = createKlixClient({
apiKey: process.env.KLIX_API_KEY!,
brandId: process.env.KLIX_BRAND_ID!,
});
const purchase = await klix.purchases.create({
currency: 'EUR',
reference: 'ORDER-1001',
client: {
email: 'customer@example.com',
},
purchase: {
products: [
{
name: 'Pro subscription',
price: 1999,
quantity: 1,
},
],
},
success_callback: 'https://example.com/api/klix/callback',
success_redirect: 'https://example.com/checkout/success',
failure_redirect: 'https://example.com/checkout/failure',
});
console.log(purchase.checkout_url);
Use a durable order reference and store the returned purchase id. Klix can return asynchronous states for capture, charge, release, and refund operations, so webhook delivery is the safest place to finalize order state.
Main API Surface
klix.balance.get();
klix.paymentMethods.list({ currency: 'EUR' });
klix.payoutMethods.list({ currency: 'EUR' });
klix.purchases.create(...);
klix.purchases.read(id);
klix.purchases.cancel(id);
klix.purchases.capture(id, { amount: 500 });
klix.purchases.charge(id, { recurring_token: token });
klix.purchases.refund(id, { client_name: 'Jane Doe', amount: 500 });
klix.purchases.release(id);
klix.clients.create(...);
klix.clients.list();
klix.clients.iterateAll();
klix.clients.listRecurringTokens(clientId);
klix.billing.sendInvoice(...);
klix.billingTemplates.create(...);
klix.billingTemplates.list();
klix.billingTemplates.addSubscriber(templateId, ...);
klix.billingTemplates.sendInvoice(templateId, ...);
klix.billingTemplates.listClients(templateId);
klix.companyStatements.create(...);
klix.companyStatements.list();
klix.webhooks.create(...);
klix.webhooks.list();
klix.webhooks.listDeliveries({ id: purchaseId, source_type: 'purchase' });
Error Handling
SDK throws KlixApiError.
import { KlixApiError } from '@biggora/klix';
try {
await klix.balance.get();
} catch (error) {
if (error instanceof KlixApiError) {
console.error(error.status, error.code, error.message, error.details);
}
}
Callback and Webhook Verification
Success callback verification
KlixClient can fetch Klix callback public key and verify callback payload signatures.
const valid = await klix.verifySuccessCallback(rawBodyBuffer, signatureHeader);
Webhook verification
For webhook deliveries, Klix provides dedicated public key per webhook.
import { verifyWebhookPayload } from '@biggora/klix';
const valid = verifyWebhookPayload(rawBodyBuffer, signatureHeader, webhook.public_key);
Create a webhook from code when you want setup to be repeatable across environments:
const webhook = await klix.webhooks.create({
title: 'Production purchase events',
callback: 'https://example.com/api/klix/webhook',
all_events: false,
events: ['purchase.paid', 'purchase.payment_failure', 'payment.refunded'],
});
console.log(webhook.public_key);
NestJS
Use @biggora/klix/nestjs subpath export.
import { Module } from '@nestjs/common';
import { KlixModule } from '@biggora/klix/nestjs';
@Module({
imports: [
KlixModule.forRoot({
apiKey: process.env.KLIX_API_KEY!,
brandId: process.env.KLIX_BRAND_ID!,
}),
],
})
export class PaymentsModule {}
Async config:
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { KlixModule } from '@biggora/klix/nestjs';
@Module({
imports: [
ConfigModule.forRoot(),
KlixModule.forRootAsync({
inject: [ConfigService],
useFactory: async (config: ConfigService) => ({
apiKey: config.getOrThrow<string>('KLIX_API_KEY'),
brandId: config.getOrThrow<string>('KLIX_BRAND_ID'),
}),
}),
],
})
export class PaymentsModule {}
Inject client into services:
import { Injectable } from '@nestjs/common';
import { InjectKlixClient } from '@biggora/klix/nestjs';
import type { KlixClient } from '@biggora/klix';
@Injectable()
export class PaymentsService {
constructor(@InjectKlixClient() private readonly klix: KlixClient) {}
async getBalance() {
return this.klix.balance.get();
}
}
Use verifier service:
import { Controller, Post, Req } from '@nestjs/common';
import type { RawBodyRequest } from '@nestjs/common';
import type { Request } from 'express';
import { KlixSignatureVerifier } from '@biggora/klix/nestjs';
@Controller('klix')
export class KlixCallbackController {
constructor(private readonly verifier: KlixSignatureVerifier) {}
@Post('callback')
async callback(@Req() req: RawBodyRequest<Request>) {
const signature = String(req.headers['x-signature'] ?? '');
const valid = await this.verifier.verifySuccessCallback(req.rawBody ?? Buffer.alloc(0), signature);
return { valid };
}
@Post('webhook')
webhook(@Req() req: RawBodyRequest<Request>) {
const signature = String(req.headers['x-signature'] ?? '');
const webhookPublicKey = process.env.KLIX_WEBHOOK_PUBLIC_KEY!;
const valid = this.verifier.verifyWebhookPayload(req.rawBody ?? Buffer.alloc(0), signature, webhookPublicKey);
return { valid };
}
}
Enable raw body before registering callback or webhook routes:
Express
const app = await NestFactory.create(AppModule, { rawBody: true });
Fastify
const app = await NestFactory.create(
AppModule,
new FastifyAdapter(),
{ rawBody: true },
);
Notes
paymentMethods.list()injects configuredbrandIdautomatically and caches results by query for 60 seconds.payoutMethods.list()also injects configuredbrandId.purchases.create()and billing template creation helpers inject configuredbrandIdwhen omitted in request body.- Source of truth for generated types is current Klix OpenAPI schema at
https://portal.klix.app/api/schema/v1/.