@konetpay/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 KonetPay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # @konetpay/core
2
+
3
+ Framework-agnostic API client for KonetPay. No DOM/browser assumptions —
4
+ works in Node backends, browsers, and React Native.
5
+
6
+ ```bash
7
+ npm install @konetpay/core
8
+ ```
9
+
10
+ ## Quick start
11
+
12
+ ```ts
13
+ // backend — secret key, initializes a transaction
14
+ import { KonetPayServerClient } from "@konetpay/core";
15
+
16
+ const konet = new KonetPayServerClient({ secretKey: process.env.KONETPAY_SECRET_KEY! });
17
+
18
+ const transaction = await konet.initializeTransaction({
19
+ amount: 500_000, // ₦5,000.00, in kobo
20
+ currency: "NGN",
21
+ customer: { email: "customer@example.com" },
22
+ });
23
+ // { reference, accessCode, authorizationUrl }
24
+ ```
25
+
26
+ ```ts
27
+ // browser or backend — publishable key, checks status
28
+ import { KonetPayClient } from "@konetpay/core";
29
+
30
+ const konet = new KonetPayClient({ publicKey: "pk_test_..." });
31
+
32
+ const result = await konet.verifyTransaction(reference);
33
+ if (result.paymentStatus === "successful") {
34
+ // fulfill the order
35
+ }
36
+ ```
37
+
38
+ `authorizationUrl` is a hosted checkout page — this package never renders
39
+ payment UI itself. To open it as an iframe overlay in a browser, see
40
+ [`@konetpay/web`](https://github.com/21st-Century-Technologies/konetpay-sdk-frontend/tree/main/packages/web).
41
+
42
+ ## Why the key split?
43
+
44
+ Only the secret key can initialize a transaction — that's what makes the
45
+ amount trustworthy, since a browser holding only the publishable key can
46
+ never create one and so can't tamper with it. The publishable key can verify
47
+ a transaction's status, a read-only operation safe to call from the browser
48
+ or your backend.
49
+
50
+ See [USAGE.md](https://github.com/21st-Century-Technologies/konetpay-sdk-frontend/blob/main/USAGE.md)
51
+ in the repo root for the full integration guide, including the
52
+ `openCheckout` → `verifyTransaction` flow end to end.
package/dist/index.cjs ADDED
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ CHECKOUT_MESSAGE_TYPE: () => CHECKOUT_MESSAGE_TYPE,
24
+ KonetPayApiError: () => KonetPayApiError,
25
+ KonetPayClient: () => KonetPayClient,
26
+ KonetPayError: () => KonetPayError,
27
+ KonetPayServerClient: () => KonetPayServerClient,
28
+ KonetPayValidationError: () => KonetPayValidationError
29
+ });
30
+ module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/errors/index.ts
33
+ var KonetPayError = class extends Error {
34
+ constructor(message, code = "unknown_error", details) {
35
+ super(message);
36
+ this.name = "KonetPayError";
37
+ this.code = code;
38
+ this.details = details;
39
+ }
40
+ };
41
+ var KonetPayApiError = class extends KonetPayError {
42
+ constructor(message, statusCode, code = "api_error", details) {
43
+ super(message, code, details);
44
+ this.name = "KonetPayApiError";
45
+ this.statusCode = statusCode;
46
+ }
47
+ };
48
+ var KonetPayValidationError = class extends KonetPayError {
49
+ constructor(message, field) {
50
+ super(message, "validation_error");
51
+ this.name = "KonetPayValidationError";
52
+ this.field = field;
53
+ }
54
+ };
55
+
56
+ // src/transport/index.ts
57
+ var DEFAULT_BASE_URLS = {
58
+ sandbox: "https://core-dev-api.konetpay.com",
59
+ live: "https://core-api.konetpay.com"
60
+ };
61
+ var HttpClient = class {
62
+ constructor(config) {
63
+ if (!config.apiKey) {
64
+ throw new KonetPayApiError("A valid API key is required to initialize this client.", 0, "missing_api_key");
65
+ }
66
+ this.apiKey = config.apiKey;
67
+ this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URLS[config.environment ?? "sandbox"];
68
+ }
69
+ async request(path, init = {}) {
70
+ const response = await fetch(`${this.baseUrl}${path}`, {
71
+ ...init,
72
+ headers: {
73
+ "Content-Type": "application/json",
74
+ Authorization: `Bearer ${this.apiKey}`,
75
+ ...init.headers
76
+ }
77
+ });
78
+ const body = await response.json().catch(() => void 0);
79
+ if (!response.ok || body?.status === "error") {
80
+ throw new KonetPayApiError(
81
+ body?.message ?? `Request to ${path} failed with status ${response.status}`,
82
+ response.status,
83
+ body?.code ?? "api_error",
84
+ body
85
+ );
86
+ }
87
+ return body?.data;
88
+ }
89
+ };
90
+
91
+ // src/client.ts
92
+ var KonetPayClient = class {
93
+ constructor(config) {
94
+ this.http = new HttpClient({
95
+ apiKey: config.publicKey,
96
+ baseUrl: config.baseUrl,
97
+ environment: config.environment
98
+ });
99
+ }
100
+ async verifyTransaction(reference) {
101
+ const raw = await this.http.request(`/api/transactions/status/${reference}/`);
102
+ return {
103
+ reference: raw.reference,
104
+ originalAmount: raw.original_amount,
105
+ paidAmount: raw.paid_amount,
106
+ totalAmount: raw.total_amount,
107
+ totalFee: raw.total_fee,
108
+ currencyCode: raw.currency_code,
109
+ currencySymbol: raw.currency_symbol,
110
+ paymentStatus: raw.payment_status,
111
+ message: raw.message,
112
+ mode: raw.mode,
113
+ paymentRedirectUrl: raw.payment_redirect_url
114
+ };
115
+ }
116
+ };
117
+
118
+ // src/validate-transaction-params.ts
119
+ function assertValidInitializeTransactionParams(params) {
120
+ if (!Number.isInteger(params.amount) || params.amount <= 0) {
121
+ throw new KonetPayValidationError("amount must be a positive integer (minor currency units).", "amount");
122
+ }
123
+ if (!params.customer?.email) {
124
+ throw new KonetPayValidationError("customer.email is required.", "customer.email");
125
+ }
126
+ }
127
+
128
+ // src/server-client.ts
129
+ var KonetPayServerClient = class {
130
+ constructor(config) {
131
+ this.http = new HttpClient({
132
+ apiKey: config.secretKey,
133
+ baseUrl: config.baseUrl,
134
+ environment: config.environment
135
+ });
136
+ }
137
+ async initializeTransaction(params) {
138
+ assertValidInitializeTransactionParams(params);
139
+ const raw = await this.http.request("/api/transactions/initialize/", {
140
+ method: "POST",
141
+ body: JSON.stringify({
142
+ amount: params.amount,
143
+ currency: params.currency,
144
+ email: params.customer.email,
145
+ customer_first_name: params.customer.firstName,
146
+ customer_last_name: params.customer.lastName,
147
+ customer_phone_number: params.customer.phoneNumber,
148
+ channels: params.channels,
149
+ fee_bearer: params.feeBearer,
150
+ metadata: params.metadata,
151
+ callback_url: params.callbackUrl
152
+ })
153
+ });
154
+ return {
155
+ reference: raw.reference,
156
+ accessCode: raw.access_code,
157
+ authorizationUrl: raw.authorization_url
158
+ };
159
+ }
160
+ };
161
+
162
+ // src/checkout/protocol.ts
163
+ var CHECKOUT_MESSAGE_TYPE = {
164
+ SUCCESS: "konetpay:checkout:success",
165
+ CLOSE: "konetpay:checkout:close",
166
+ ERROR: "konetpay:checkout:error"
167
+ };
168
+ // Annotate the CommonJS export names for ESM import in node:
169
+ 0 && (module.exports = {
170
+ CHECKOUT_MESSAGE_TYPE,
171
+ KonetPayApiError,
172
+ KonetPayClient,
173
+ KonetPayError,
174
+ KonetPayServerClient,
175
+ KonetPayValidationError
176
+ });
177
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors/index.ts","../src/transport/index.ts","../src/client.ts","../src/validate-transaction-params.ts","../src/server-client.ts","../src/checkout/protocol.ts"],"sourcesContent":["export { KonetPayClient } from \"./client\";\nexport type { KonetPayClientConfig } from \"./client\";\n\nexport { KonetPayServerClient } from \"./server-client\";\nexport type { KonetPayServerClientConfig } from \"./server-client\";\n\nexport * from \"./types\";\nexport * from \"./errors\";\nexport * from \"./checkout/protocol\";\n","export class KonetPayError extends Error {\n readonly code: string;\n readonly details?: unknown;\n\n constructor(message: string, code = \"unknown_error\", details?: unknown) {\n super(message);\n this.name = \"KonetPayError\";\n this.code = code;\n this.details = details;\n }\n}\n\nexport class KonetPayApiError extends KonetPayError {\n readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code = \"api_error\", details?: unknown) {\n super(message, code, details);\n this.name = \"KonetPayApiError\";\n this.statusCode = statusCode;\n }\n}\n\nexport class KonetPayValidationError extends KonetPayError {\n readonly field?: string;\n\n constructor(message: string, field?: string) {\n super(message, \"validation_error\");\n this.name = \"KonetPayValidationError\";\n this.field = field;\n }\n}\n","import { KonetPayApiError } from \"../errors\";\n\nexport interface HttpClientConfig {\n apiKey: string;\n baseUrl?: string;\n environment?: \"sandbox\" | \"live\";\n}\n\nconst DEFAULT_BASE_URLS: Record<\"sandbox\" | \"live\", string> = {\n sandbox: \"https://core-dev-api.konetpay.com\",\n live: \"https://core-api.konetpay.com\",\n};\n\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n\n constructor(config: HttpClientConfig) {\n if (!config.apiKey) {\n throw new KonetPayApiError(\"A valid API key is required to initialize this client.\", 0, \"missing_api_key\");\n }\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URLS[config.environment ?? \"sandbox\"];\n }\n\n async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n ...init.headers,\n },\n });\n\n const body = await response.json().catch(() => undefined);\n\n if (!response.ok || body?.status === \"error\") {\n throw new KonetPayApiError(\n body?.message ?? `Request to ${path} failed with status ${response.status}`,\n response.status,\n body?.code ?? \"api_error\",\n body,\n );\n }\n\n // Every response is wrapped as { status, message, data }.\n return body?.data as T;\n }\n}\n","import { HttpClient } from \"./transport\";\nimport type { Currency, PaymentStatus, VerifyTransactionResult } from \"./types\";\n\nexport interface KonetPayClientConfig {\n /** Publishable key — safe to ship in a browser bundle. Never put a secret key here. */\n publicKey: string;\n baseUrl?: string;\n environment?: \"sandbox\" | \"live\";\n}\n\n/**\n * Browser-safe client. Initializing a transaction requires a secret key and\n * lives on KonetPayServerClient instead, which must only run on your\n * backend. This client only checks transaction status — that's safe with a\n * publishable key, so it can be called directly from the browser or from\n * your backend, whichever suits your flow.\n */\nexport class KonetPayClient {\n private readonly http: HttpClient;\n\n constructor(config: KonetPayClientConfig) {\n this.http = new HttpClient({\n apiKey: config.publicKey,\n baseUrl: config.baseUrl,\n environment: config.environment,\n });\n }\n\n async verifyTransaction(reference: string): Promise<VerifyTransactionResult> {\n // Not /api/transactions/verify/ — that endpoint is secret-key-gated and\n // returns an unrelated webhook-payload shape. This is the one publishable\n // keys can actually call, and the one the hosted checkout page itself uses.\n const raw = await this.http.request<RawVerifyTransactionResponse>(`/api/transactions/status/${reference}/`);\n return {\n reference: raw.reference,\n originalAmount: raw.original_amount,\n paidAmount: raw.paid_amount,\n totalAmount: raw.total_amount,\n totalFee: raw.total_fee,\n currencyCode: raw.currency_code,\n currencySymbol: raw.currency_symbol,\n paymentStatus: raw.payment_status,\n message: raw.message,\n mode: raw.mode,\n paymentRedirectUrl: raw.payment_redirect_url,\n };\n }\n}\n\n/** Wire shape — the API returns snake_case, the SDK exposes camelCase. */\ninterface RawVerifyTransactionResponse {\n reference: string;\n original_amount: number;\n paid_amount: number;\n total_amount: number;\n total_fee: number;\n currency_code: Currency;\n currency_symbol: string;\n payment_status: PaymentStatus;\n message: string;\n mode: \"test\" | \"live\";\n payment_redirect_url: string | null;\n}\n","import { KonetPayValidationError } from \"./errors\";\nimport type { InitializeTransactionParams } from \"./types\";\n\nexport function assertValidInitializeTransactionParams(params: InitializeTransactionParams): void {\n if (!Number.isInteger(params.amount) || params.amount <= 0) {\n throw new KonetPayValidationError(\"amount must be a positive integer (minor currency units).\", \"amount\");\n }\n if (!params.customer?.email) {\n throw new KonetPayValidationError(\"customer.email is required.\", \"customer.email\");\n }\n}\n","import { HttpClient } from \"./transport\";\nimport { assertValidInitializeTransactionParams } from \"./validate-transaction-params\";\nimport type { InitializeTransactionParams, InitializeTransactionResult } from \"./types\";\n\nexport interface KonetPayServerClientConfig {\n /** Secret key — backend-only. Never ship this to a browser bundle. */\n secretKey: string;\n baseUrl?: string;\n environment?: \"sandbox\" | \"live\";\n}\n\n/**\n * Backend-only client. Requires a secret key, so it must never run in a\n * browser bundle or React Native app. Only the secret key can initialize a\n * transaction — this is what makes the amount trustworthy, since the client\n * never sees this key or picks the amount itself.\n */\nexport class KonetPayServerClient {\n private readonly http: HttpClient;\n\n constructor(config: KonetPayServerClientConfig) {\n this.http = new HttpClient({\n apiKey: config.secretKey,\n baseUrl: config.baseUrl,\n environment: config.environment,\n });\n }\n\n async initializeTransaction(params: InitializeTransactionParams): Promise<InitializeTransactionResult> {\n assertValidInitializeTransactionParams(params);\n const raw = await this.http.request<RawInitializeTransactionResponse>(\"/api/transactions/initialize/\", {\n method: \"POST\",\n body: JSON.stringify({\n amount: params.amount,\n currency: params.currency,\n email: params.customer.email,\n customer_first_name: params.customer.firstName,\n customer_last_name: params.customer.lastName,\n customer_phone_number: params.customer.phoneNumber,\n channels: params.channels,\n fee_bearer: params.feeBearer,\n metadata: params.metadata,\n callback_url: params.callbackUrl,\n }),\n });\n return {\n reference: raw.reference,\n accessCode: raw.access_code,\n authorizationUrl: raw.authorization_url,\n };\n }\n}\n\n/** Wire shape — the API returns snake_case, the SDK exposes camelCase. */\ninterface RawInitializeTransactionResponse {\n reference: string;\n access_code: string;\n authorization_url: string;\n}\n","/**\n * Message contract between the hosted checkout page and any SDK-side trigger\n * (browser iframe overlay via postMessage, React Native via a WebView bridge, ...).\n * Kept here, not in a platform package, so every transport agrees on the same shape.\n */\nexport const CHECKOUT_MESSAGE_TYPE = {\n SUCCESS: \"konetpay:checkout:success\",\n CLOSE: \"konetpay:checkout:close\",\n ERROR: \"konetpay:checkout:error\",\n} as const;\n\nexport interface CheckoutSuccessMessage {\n type: typeof CHECKOUT_MESSAGE_TYPE.SUCCESS;\n reference: string;\n}\n\nexport interface CheckoutCloseMessage {\n type: typeof CHECKOUT_MESSAGE_TYPE.CLOSE;\n}\n\nexport interface CheckoutErrorMessage {\n type: typeof CHECKOUT_MESSAGE_TYPE.ERROR;\n reference: string;\n message?: string;\n}\n\nexport type CheckoutMessage = CheckoutSuccessMessage | CheckoutCloseMessage | CheckoutErrorMessage;\n\nexport type CheckoutResult =\n | { status: \"success\"; reference: string }\n | { status: \"cancelled\" }\n | { status: \"error\"; reference: string; message?: string };\n"],"mappings":"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","names":[]}
@@ -0,0 +1,135 @@
1
+ type Currency = "NGN" | "USD" | "GBP" | "EUR";
2
+ type PaymentMethodType = "card" | "bank_transfer";
3
+ /** Who pays the transaction fee. Extend as the API adds more values. */
4
+ type FeeBearer = "merchant" | "customer" | (string & {});
5
+ /**
6
+ * Known values seen from the API so far — treated as an open string union
7
+ * since the full set hasn't been confirmed. Widen this as more are observed.
8
+ */
9
+ type PaymentStatus = "abandoned" | "pending" | "successful" | "failed" | "expired" | (string & {});
10
+ interface TransactionCustomer {
11
+ email: string;
12
+ firstName?: string;
13
+ lastName?: string;
14
+ phoneNumber?: string;
15
+ }
16
+ interface InitializeTransactionParams {
17
+ /** Positive integer, minor currency units (e.g. kobo, not naira). */
18
+ amount: number;
19
+ currency: Currency;
20
+ customer: TransactionCustomer;
21
+ /** Restrict which payment methods the hosted checkout offers. Omit to allow all enabled methods. */
22
+ channels?: PaymentMethodType[];
23
+ feeBearer?: FeeBearer;
24
+ metadata?: Record<string, unknown>;
25
+ /** Where the API's own redirect fallback points after payment (?reference=&status=). Omit to fall back to the business's configured default redirect URL. Separate from this SDK's iframe/postMessage flow. */
26
+ callbackUrl?: string;
27
+ }
28
+ interface InitializeTransactionResult {
29
+ reference: string;
30
+ accessCode: string;
31
+ /** The hosted checkout page to open in a popup/iframe/redirect — never rendered by this SDK. */
32
+ authorizationUrl: string;
33
+ }
34
+ interface VerifyTransactionResult {
35
+ reference: string;
36
+ /** Amounts below are in MAJOR currency units (e.g. naira, not kobo) — unlike InitializeTransactionParams.amount. */
37
+ originalAmount: number;
38
+ paidAmount: number;
39
+ totalAmount: number;
40
+ totalFee: number;
41
+ currencyCode: Currency;
42
+ currencySymbol: string;
43
+ paymentStatus: PaymentStatus;
44
+ message: string;
45
+ mode: "test" | "live";
46
+ /** Merchant's post-payment redirect URL (`?reference=&status=`), populated only once the transaction reaches a terminal status. This is the same fallback the hosted checkout page redirects to when it wasn't opened inside the SDK's iframe. */
47
+ paymentRedirectUrl: string | null;
48
+ }
49
+
50
+ interface KonetPayClientConfig {
51
+ /** Publishable key — safe to ship in a browser bundle. Never put a secret key here. */
52
+ publicKey: string;
53
+ baseUrl?: string;
54
+ environment?: "sandbox" | "live";
55
+ }
56
+ /**
57
+ * Browser-safe client. Initializing a transaction requires a secret key and
58
+ * lives on KonetPayServerClient instead, which must only run on your
59
+ * backend. This client only checks transaction status — that's safe with a
60
+ * publishable key, so it can be called directly from the browser or from
61
+ * your backend, whichever suits your flow.
62
+ */
63
+ declare class KonetPayClient {
64
+ private readonly http;
65
+ constructor(config: KonetPayClientConfig);
66
+ verifyTransaction(reference: string): Promise<VerifyTransactionResult>;
67
+ }
68
+
69
+ interface KonetPayServerClientConfig {
70
+ /** Secret key — backend-only. Never ship this to a browser bundle. */
71
+ secretKey: string;
72
+ baseUrl?: string;
73
+ environment?: "sandbox" | "live";
74
+ }
75
+ /**
76
+ * Backend-only client. Requires a secret key, so it must never run in a
77
+ * browser bundle or React Native app. Only the secret key can initialize a
78
+ * transaction — this is what makes the amount trustworthy, since the client
79
+ * never sees this key or picks the amount itself.
80
+ */
81
+ declare class KonetPayServerClient {
82
+ private readonly http;
83
+ constructor(config: KonetPayServerClientConfig);
84
+ initializeTransaction(params: InitializeTransactionParams): Promise<InitializeTransactionResult>;
85
+ }
86
+
87
+ declare class KonetPayError extends Error {
88
+ readonly code: string;
89
+ readonly details?: unknown;
90
+ constructor(message: string, code?: string, details?: unknown);
91
+ }
92
+ declare class KonetPayApiError extends KonetPayError {
93
+ readonly statusCode: number;
94
+ constructor(message: string, statusCode: number, code?: string, details?: unknown);
95
+ }
96
+ declare class KonetPayValidationError extends KonetPayError {
97
+ readonly field?: string;
98
+ constructor(message: string, field?: string);
99
+ }
100
+
101
+ /**
102
+ * Message contract between the hosted checkout page and any SDK-side trigger
103
+ * (browser iframe overlay via postMessage, React Native via a WebView bridge, ...).
104
+ * Kept here, not in a platform package, so every transport agrees on the same shape.
105
+ */
106
+ declare const CHECKOUT_MESSAGE_TYPE: {
107
+ readonly SUCCESS: "konetpay:checkout:success";
108
+ readonly CLOSE: "konetpay:checkout:close";
109
+ readonly ERROR: "konetpay:checkout:error";
110
+ };
111
+ interface CheckoutSuccessMessage {
112
+ type: typeof CHECKOUT_MESSAGE_TYPE.SUCCESS;
113
+ reference: string;
114
+ }
115
+ interface CheckoutCloseMessage {
116
+ type: typeof CHECKOUT_MESSAGE_TYPE.CLOSE;
117
+ }
118
+ interface CheckoutErrorMessage {
119
+ type: typeof CHECKOUT_MESSAGE_TYPE.ERROR;
120
+ reference: string;
121
+ message?: string;
122
+ }
123
+ type CheckoutMessage = CheckoutSuccessMessage | CheckoutCloseMessage | CheckoutErrorMessage;
124
+ type CheckoutResult = {
125
+ status: "success";
126
+ reference: string;
127
+ } | {
128
+ status: "cancelled";
129
+ } | {
130
+ status: "error";
131
+ reference: string;
132
+ message?: string;
133
+ };
134
+
135
+ export { CHECKOUT_MESSAGE_TYPE, type CheckoutCloseMessage, type CheckoutErrorMessage, type CheckoutMessage, type CheckoutResult, type CheckoutSuccessMessage, type Currency, type FeeBearer, type InitializeTransactionParams, type InitializeTransactionResult, KonetPayApiError, KonetPayClient, type KonetPayClientConfig, KonetPayError, KonetPayServerClient, type KonetPayServerClientConfig, KonetPayValidationError, type PaymentMethodType, type PaymentStatus, type TransactionCustomer, type VerifyTransactionResult };
@@ -0,0 +1,135 @@
1
+ type Currency = "NGN" | "USD" | "GBP" | "EUR";
2
+ type PaymentMethodType = "card" | "bank_transfer";
3
+ /** Who pays the transaction fee. Extend as the API adds more values. */
4
+ type FeeBearer = "merchant" | "customer" | (string & {});
5
+ /**
6
+ * Known values seen from the API so far — treated as an open string union
7
+ * since the full set hasn't been confirmed. Widen this as more are observed.
8
+ */
9
+ type PaymentStatus = "abandoned" | "pending" | "successful" | "failed" | "expired" | (string & {});
10
+ interface TransactionCustomer {
11
+ email: string;
12
+ firstName?: string;
13
+ lastName?: string;
14
+ phoneNumber?: string;
15
+ }
16
+ interface InitializeTransactionParams {
17
+ /** Positive integer, minor currency units (e.g. kobo, not naira). */
18
+ amount: number;
19
+ currency: Currency;
20
+ customer: TransactionCustomer;
21
+ /** Restrict which payment methods the hosted checkout offers. Omit to allow all enabled methods. */
22
+ channels?: PaymentMethodType[];
23
+ feeBearer?: FeeBearer;
24
+ metadata?: Record<string, unknown>;
25
+ /** Where the API's own redirect fallback points after payment (?reference=&status=). Omit to fall back to the business's configured default redirect URL. Separate from this SDK's iframe/postMessage flow. */
26
+ callbackUrl?: string;
27
+ }
28
+ interface InitializeTransactionResult {
29
+ reference: string;
30
+ accessCode: string;
31
+ /** The hosted checkout page to open in a popup/iframe/redirect — never rendered by this SDK. */
32
+ authorizationUrl: string;
33
+ }
34
+ interface VerifyTransactionResult {
35
+ reference: string;
36
+ /** Amounts below are in MAJOR currency units (e.g. naira, not kobo) — unlike InitializeTransactionParams.amount. */
37
+ originalAmount: number;
38
+ paidAmount: number;
39
+ totalAmount: number;
40
+ totalFee: number;
41
+ currencyCode: Currency;
42
+ currencySymbol: string;
43
+ paymentStatus: PaymentStatus;
44
+ message: string;
45
+ mode: "test" | "live";
46
+ /** Merchant's post-payment redirect URL (`?reference=&status=`), populated only once the transaction reaches a terminal status. This is the same fallback the hosted checkout page redirects to when it wasn't opened inside the SDK's iframe. */
47
+ paymentRedirectUrl: string | null;
48
+ }
49
+
50
+ interface KonetPayClientConfig {
51
+ /** Publishable key — safe to ship in a browser bundle. Never put a secret key here. */
52
+ publicKey: string;
53
+ baseUrl?: string;
54
+ environment?: "sandbox" | "live";
55
+ }
56
+ /**
57
+ * Browser-safe client. Initializing a transaction requires a secret key and
58
+ * lives on KonetPayServerClient instead, which must only run on your
59
+ * backend. This client only checks transaction status — that's safe with a
60
+ * publishable key, so it can be called directly from the browser or from
61
+ * your backend, whichever suits your flow.
62
+ */
63
+ declare class KonetPayClient {
64
+ private readonly http;
65
+ constructor(config: KonetPayClientConfig);
66
+ verifyTransaction(reference: string): Promise<VerifyTransactionResult>;
67
+ }
68
+
69
+ interface KonetPayServerClientConfig {
70
+ /** Secret key — backend-only. Never ship this to a browser bundle. */
71
+ secretKey: string;
72
+ baseUrl?: string;
73
+ environment?: "sandbox" | "live";
74
+ }
75
+ /**
76
+ * Backend-only client. Requires a secret key, so it must never run in a
77
+ * browser bundle or React Native app. Only the secret key can initialize a
78
+ * transaction — this is what makes the amount trustworthy, since the client
79
+ * never sees this key or picks the amount itself.
80
+ */
81
+ declare class KonetPayServerClient {
82
+ private readonly http;
83
+ constructor(config: KonetPayServerClientConfig);
84
+ initializeTransaction(params: InitializeTransactionParams): Promise<InitializeTransactionResult>;
85
+ }
86
+
87
+ declare class KonetPayError extends Error {
88
+ readonly code: string;
89
+ readonly details?: unknown;
90
+ constructor(message: string, code?: string, details?: unknown);
91
+ }
92
+ declare class KonetPayApiError extends KonetPayError {
93
+ readonly statusCode: number;
94
+ constructor(message: string, statusCode: number, code?: string, details?: unknown);
95
+ }
96
+ declare class KonetPayValidationError extends KonetPayError {
97
+ readonly field?: string;
98
+ constructor(message: string, field?: string);
99
+ }
100
+
101
+ /**
102
+ * Message contract between the hosted checkout page and any SDK-side trigger
103
+ * (browser iframe overlay via postMessage, React Native via a WebView bridge, ...).
104
+ * Kept here, not in a platform package, so every transport agrees on the same shape.
105
+ */
106
+ declare const CHECKOUT_MESSAGE_TYPE: {
107
+ readonly SUCCESS: "konetpay:checkout:success";
108
+ readonly CLOSE: "konetpay:checkout:close";
109
+ readonly ERROR: "konetpay:checkout:error";
110
+ };
111
+ interface CheckoutSuccessMessage {
112
+ type: typeof CHECKOUT_MESSAGE_TYPE.SUCCESS;
113
+ reference: string;
114
+ }
115
+ interface CheckoutCloseMessage {
116
+ type: typeof CHECKOUT_MESSAGE_TYPE.CLOSE;
117
+ }
118
+ interface CheckoutErrorMessage {
119
+ type: typeof CHECKOUT_MESSAGE_TYPE.ERROR;
120
+ reference: string;
121
+ message?: string;
122
+ }
123
+ type CheckoutMessage = CheckoutSuccessMessage | CheckoutCloseMessage | CheckoutErrorMessage;
124
+ type CheckoutResult = {
125
+ status: "success";
126
+ reference: string;
127
+ } | {
128
+ status: "cancelled";
129
+ } | {
130
+ status: "error";
131
+ reference: string;
132
+ message?: string;
133
+ };
134
+
135
+ export { CHECKOUT_MESSAGE_TYPE, type CheckoutCloseMessage, type CheckoutErrorMessage, type CheckoutMessage, type CheckoutResult, type CheckoutSuccessMessage, type Currency, type FeeBearer, type InitializeTransactionParams, type InitializeTransactionResult, KonetPayApiError, KonetPayClient, type KonetPayClientConfig, KonetPayError, KonetPayServerClient, type KonetPayServerClientConfig, KonetPayValidationError, type PaymentMethodType, type PaymentStatus, type TransactionCustomer, type VerifyTransactionResult };
package/dist/index.js ADDED
@@ -0,0 +1,145 @@
1
+ // src/errors/index.ts
2
+ var KonetPayError = class extends Error {
3
+ constructor(message, code = "unknown_error", details) {
4
+ super(message);
5
+ this.name = "KonetPayError";
6
+ this.code = code;
7
+ this.details = details;
8
+ }
9
+ };
10
+ var KonetPayApiError = class extends KonetPayError {
11
+ constructor(message, statusCode, code = "api_error", details) {
12
+ super(message, code, details);
13
+ this.name = "KonetPayApiError";
14
+ this.statusCode = statusCode;
15
+ }
16
+ };
17
+ var KonetPayValidationError = class extends KonetPayError {
18
+ constructor(message, field) {
19
+ super(message, "validation_error");
20
+ this.name = "KonetPayValidationError";
21
+ this.field = field;
22
+ }
23
+ };
24
+
25
+ // src/transport/index.ts
26
+ var DEFAULT_BASE_URLS = {
27
+ sandbox: "https://core-dev-api.konetpay.com",
28
+ live: "https://core-api.konetpay.com"
29
+ };
30
+ var HttpClient = class {
31
+ constructor(config) {
32
+ if (!config.apiKey) {
33
+ throw new KonetPayApiError("A valid API key is required to initialize this client.", 0, "missing_api_key");
34
+ }
35
+ this.apiKey = config.apiKey;
36
+ this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URLS[config.environment ?? "sandbox"];
37
+ }
38
+ async request(path, init = {}) {
39
+ const response = await fetch(`${this.baseUrl}${path}`, {
40
+ ...init,
41
+ headers: {
42
+ "Content-Type": "application/json",
43
+ Authorization: `Bearer ${this.apiKey}`,
44
+ ...init.headers
45
+ }
46
+ });
47
+ const body = await response.json().catch(() => void 0);
48
+ if (!response.ok || body?.status === "error") {
49
+ throw new KonetPayApiError(
50
+ body?.message ?? `Request to ${path} failed with status ${response.status}`,
51
+ response.status,
52
+ body?.code ?? "api_error",
53
+ body
54
+ );
55
+ }
56
+ return body?.data;
57
+ }
58
+ };
59
+
60
+ // src/client.ts
61
+ var KonetPayClient = class {
62
+ constructor(config) {
63
+ this.http = new HttpClient({
64
+ apiKey: config.publicKey,
65
+ baseUrl: config.baseUrl,
66
+ environment: config.environment
67
+ });
68
+ }
69
+ async verifyTransaction(reference) {
70
+ const raw = await this.http.request(`/api/transactions/status/${reference}/`);
71
+ return {
72
+ reference: raw.reference,
73
+ originalAmount: raw.original_amount,
74
+ paidAmount: raw.paid_amount,
75
+ totalAmount: raw.total_amount,
76
+ totalFee: raw.total_fee,
77
+ currencyCode: raw.currency_code,
78
+ currencySymbol: raw.currency_symbol,
79
+ paymentStatus: raw.payment_status,
80
+ message: raw.message,
81
+ mode: raw.mode,
82
+ paymentRedirectUrl: raw.payment_redirect_url
83
+ };
84
+ }
85
+ };
86
+
87
+ // src/validate-transaction-params.ts
88
+ function assertValidInitializeTransactionParams(params) {
89
+ if (!Number.isInteger(params.amount) || params.amount <= 0) {
90
+ throw new KonetPayValidationError("amount must be a positive integer (minor currency units).", "amount");
91
+ }
92
+ if (!params.customer?.email) {
93
+ throw new KonetPayValidationError("customer.email is required.", "customer.email");
94
+ }
95
+ }
96
+
97
+ // src/server-client.ts
98
+ var KonetPayServerClient = class {
99
+ constructor(config) {
100
+ this.http = new HttpClient({
101
+ apiKey: config.secretKey,
102
+ baseUrl: config.baseUrl,
103
+ environment: config.environment
104
+ });
105
+ }
106
+ async initializeTransaction(params) {
107
+ assertValidInitializeTransactionParams(params);
108
+ const raw = await this.http.request("/api/transactions/initialize/", {
109
+ method: "POST",
110
+ body: JSON.stringify({
111
+ amount: params.amount,
112
+ currency: params.currency,
113
+ email: params.customer.email,
114
+ customer_first_name: params.customer.firstName,
115
+ customer_last_name: params.customer.lastName,
116
+ customer_phone_number: params.customer.phoneNumber,
117
+ channels: params.channels,
118
+ fee_bearer: params.feeBearer,
119
+ metadata: params.metadata,
120
+ callback_url: params.callbackUrl
121
+ })
122
+ });
123
+ return {
124
+ reference: raw.reference,
125
+ accessCode: raw.access_code,
126
+ authorizationUrl: raw.authorization_url
127
+ };
128
+ }
129
+ };
130
+
131
+ // src/checkout/protocol.ts
132
+ var CHECKOUT_MESSAGE_TYPE = {
133
+ SUCCESS: "konetpay:checkout:success",
134
+ CLOSE: "konetpay:checkout:close",
135
+ ERROR: "konetpay:checkout:error"
136
+ };
137
+ export {
138
+ CHECKOUT_MESSAGE_TYPE,
139
+ KonetPayApiError,
140
+ KonetPayClient,
141
+ KonetPayError,
142
+ KonetPayServerClient,
143
+ KonetPayValidationError
144
+ };
145
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors/index.ts","../src/transport/index.ts","../src/client.ts","../src/validate-transaction-params.ts","../src/server-client.ts","../src/checkout/protocol.ts"],"sourcesContent":["export class KonetPayError extends Error {\n readonly code: string;\n readonly details?: unknown;\n\n constructor(message: string, code = \"unknown_error\", details?: unknown) {\n super(message);\n this.name = \"KonetPayError\";\n this.code = code;\n this.details = details;\n }\n}\n\nexport class KonetPayApiError extends KonetPayError {\n readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code = \"api_error\", details?: unknown) {\n super(message, code, details);\n this.name = \"KonetPayApiError\";\n this.statusCode = statusCode;\n }\n}\n\nexport class KonetPayValidationError extends KonetPayError {\n readonly field?: string;\n\n constructor(message: string, field?: string) {\n super(message, \"validation_error\");\n this.name = \"KonetPayValidationError\";\n this.field = field;\n }\n}\n","import { KonetPayApiError } from \"../errors\";\n\nexport interface HttpClientConfig {\n apiKey: string;\n baseUrl?: string;\n environment?: \"sandbox\" | \"live\";\n}\n\nconst DEFAULT_BASE_URLS: Record<\"sandbox\" | \"live\", string> = {\n sandbox: \"https://core-dev-api.konetpay.com\",\n live: \"https://core-api.konetpay.com\",\n};\n\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n\n constructor(config: HttpClientConfig) {\n if (!config.apiKey) {\n throw new KonetPayApiError(\"A valid API key is required to initialize this client.\", 0, \"missing_api_key\");\n }\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URLS[config.environment ?? \"sandbox\"];\n }\n\n async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n ...init.headers,\n },\n });\n\n const body = await response.json().catch(() => undefined);\n\n if (!response.ok || body?.status === \"error\") {\n throw new KonetPayApiError(\n body?.message ?? `Request to ${path} failed with status ${response.status}`,\n response.status,\n body?.code ?? \"api_error\",\n body,\n );\n }\n\n // Every response is wrapped as { status, message, data }.\n return body?.data as T;\n }\n}\n","import { HttpClient } from \"./transport\";\nimport type { Currency, PaymentStatus, VerifyTransactionResult } from \"./types\";\n\nexport interface KonetPayClientConfig {\n /** Publishable key — safe to ship in a browser bundle. Never put a secret key here. */\n publicKey: string;\n baseUrl?: string;\n environment?: \"sandbox\" | \"live\";\n}\n\n/**\n * Browser-safe client. Initializing a transaction requires a secret key and\n * lives on KonetPayServerClient instead, which must only run on your\n * backend. This client only checks transaction status — that's safe with a\n * publishable key, so it can be called directly from the browser or from\n * your backend, whichever suits your flow.\n */\nexport class KonetPayClient {\n private readonly http: HttpClient;\n\n constructor(config: KonetPayClientConfig) {\n this.http = new HttpClient({\n apiKey: config.publicKey,\n baseUrl: config.baseUrl,\n environment: config.environment,\n });\n }\n\n async verifyTransaction(reference: string): Promise<VerifyTransactionResult> {\n // Not /api/transactions/verify/ — that endpoint is secret-key-gated and\n // returns an unrelated webhook-payload shape. This is the one publishable\n // keys can actually call, and the one the hosted checkout page itself uses.\n const raw = await this.http.request<RawVerifyTransactionResponse>(`/api/transactions/status/${reference}/`);\n return {\n reference: raw.reference,\n originalAmount: raw.original_amount,\n paidAmount: raw.paid_amount,\n totalAmount: raw.total_amount,\n totalFee: raw.total_fee,\n currencyCode: raw.currency_code,\n currencySymbol: raw.currency_symbol,\n paymentStatus: raw.payment_status,\n message: raw.message,\n mode: raw.mode,\n paymentRedirectUrl: raw.payment_redirect_url,\n };\n }\n}\n\n/** Wire shape — the API returns snake_case, the SDK exposes camelCase. */\ninterface RawVerifyTransactionResponse {\n reference: string;\n original_amount: number;\n paid_amount: number;\n total_amount: number;\n total_fee: number;\n currency_code: Currency;\n currency_symbol: string;\n payment_status: PaymentStatus;\n message: string;\n mode: \"test\" | \"live\";\n payment_redirect_url: string | null;\n}\n","import { KonetPayValidationError } from \"./errors\";\nimport type { InitializeTransactionParams } from \"./types\";\n\nexport function assertValidInitializeTransactionParams(params: InitializeTransactionParams): void {\n if (!Number.isInteger(params.amount) || params.amount <= 0) {\n throw new KonetPayValidationError(\"amount must be a positive integer (minor currency units).\", \"amount\");\n }\n if (!params.customer?.email) {\n throw new KonetPayValidationError(\"customer.email is required.\", \"customer.email\");\n }\n}\n","import { HttpClient } from \"./transport\";\nimport { assertValidInitializeTransactionParams } from \"./validate-transaction-params\";\nimport type { InitializeTransactionParams, InitializeTransactionResult } from \"./types\";\n\nexport interface KonetPayServerClientConfig {\n /** Secret key — backend-only. Never ship this to a browser bundle. */\n secretKey: string;\n baseUrl?: string;\n environment?: \"sandbox\" | \"live\";\n}\n\n/**\n * Backend-only client. Requires a secret key, so it must never run in a\n * browser bundle or React Native app. Only the secret key can initialize a\n * transaction — this is what makes the amount trustworthy, since the client\n * never sees this key or picks the amount itself.\n */\nexport class KonetPayServerClient {\n private readonly http: HttpClient;\n\n constructor(config: KonetPayServerClientConfig) {\n this.http = new HttpClient({\n apiKey: config.secretKey,\n baseUrl: config.baseUrl,\n environment: config.environment,\n });\n }\n\n async initializeTransaction(params: InitializeTransactionParams): Promise<InitializeTransactionResult> {\n assertValidInitializeTransactionParams(params);\n const raw = await this.http.request<RawInitializeTransactionResponse>(\"/api/transactions/initialize/\", {\n method: \"POST\",\n body: JSON.stringify({\n amount: params.amount,\n currency: params.currency,\n email: params.customer.email,\n customer_first_name: params.customer.firstName,\n customer_last_name: params.customer.lastName,\n customer_phone_number: params.customer.phoneNumber,\n channels: params.channels,\n fee_bearer: params.feeBearer,\n metadata: params.metadata,\n callback_url: params.callbackUrl,\n }),\n });\n return {\n reference: raw.reference,\n accessCode: raw.access_code,\n authorizationUrl: raw.authorization_url,\n };\n }\n}\n\n/** Wire shape — the API returns snake_case, the SDK exposes camelCase. */\ninterface RawInitializeTransactionResponse {\n reference: string;\n access_code: string;\n authorization_url: string;\n}\n","/**\n * Message contract between the hosted checkout page and any SDK-side trigger\n * (browser iframe overlay via postMessage, React Native via a WebView bridge, ...).\n * Kept here, not in a platform package, so every transport agrees on the same shape.\n */\nexport const CHECKOUT_MESSAGE_TYPE = {\n SUCCESS: \"konetpay:checkout:success\",\n CLOSE: \"konetpay:checkout:close\",\n ERROR: \"konetpay:checkout:error\",\n} as const;\n\nexport interface CheckoutSuccessMessage {\n type: typeof CHECKOUT_MESSAGE_TYPE.SUCCESS;\n reference: string;\n}\n\nexport interface CheckoutCloseMessage {\n type: typeof CHECKOUT_MESSAGE_TYPE.CLOSE;\n}\n\nexport interface CheckoutErrorMessage {\n type: typeof CHECKOUT_MESSAGE_TYPE.ERROR;\n reference: string;\n message?: string;\n}\n\nexport type CheckoutMessage = CheckoutSuccessMessage | CheckoutCloseMessage | CheckoutErrorMessage;\n\nexport type CheckoutResult =\n | { status: \"success\"; reference: string }\n | { status: \"cancelled\" }\n | { status: \"error\"; reference: string; message?: string };\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@konetpay/core",
3
+ "version": "0.1.0",
4
+ "description": "Framework-agnostic core client for KonetPay: API client and the checkout protocol shared by platform-specific triggers.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/21st-Century-Technologies/konetpay-sdk-frontend.git",
9
+ "directory": "packages/core"
10
+ },
11
+ "homepage": "https://github.com/21st-Century-Technologies/konetpay-sdk-frontend/tree/main/packages/core#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/21st-Century-Technologies/konetpay-sdk-frontend/issues"
14
+ },
15
+ "keywords": [
16
+ "konetpay",
17
+ "payments",
18
+ "checkout",
19
+ "payment-gateway",
20
+ "nigeria",
21
+ "sdk"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "type": "module",
27
+ "main": "./dist/index.cjs",
28
+ "module": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/index.js",
34
+ "require": "./dist/index.cjs"
35
+ }
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "sideEffects": false,
41
+ "engines": {
42
+ "node": ">=18"
43
+ },
44
+ "scripts": {
45
+ "build": "tsup",
46
+ "dev": "tsup --watch",
47
+ "test": "vitest run --passWithNoTests",
48
+ "typecheck": "tsc --noEmit",
49
+ "clean": "rm -rf dist",
50
+ "prepublishOnly": "npm run build"
51
+ },
52
+ "devDependencies": {
53
+ "tsup": "^8.2.4",
54
+ "typescript": "^5.5.4",
55
+ "vitest": "^2.0.5"
56
+ }
57
+ }