@kerembay9/horizon-pay 1.0.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/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # horizon-pay
2
+
3
+ TypeScript/JavaScript client for the **Horizon Zeta Payment** API. Create sessions, get payment info, build checkout URLs, and complete payments with a simple, typed API.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install horizon-pay
9
+ ```
10
+
11
+ Requires Node 18+ (uses native `fetch`) or any browser with `fetch`.
12
+
13
+ ## Setup
14
+
15
+ ```ts
16
+ import { PaymentClient } from "horizon-pay";
17
+
18
+ const client = new PaymentClient({
19
+ baseUrl: "https://pay.horizonzeta.com",
20
+ apiKey: "sk_your_api_key_here", // required for createSession
21
+ });
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### Backend: create session and return checkout URL
27
+
28
+ ```ts
29
+ const { token } = await client.createSession({
30
+ amount: 99.99,
31
+ payerEmail: "user@example.com",
32
+ currency: "TL",
33
+ successRedirectUrl: "https://yoursite.com/success",
34
+ failRedirectUrl: "https://yoursite.com/failed",
35
+ webhookUrl: "https://yoursite.com/webhooks/payment", // optional
36
+ metadata: { plan: "pro", userId: "123" }, // optional
37
+ });
38
+
39
+ const checkoutUrl = client.getCheckoutUrl(token, "tr"); // or "en"
40
+ // Redirect the user to checkoutUrl.
41
+ ```
42
+
43
+ ### Frontend (or Node): get payment info and complete payment
44
+
45
+ ```ts
46
+ // Get session info (e.g. token from URL query)
47
+ const info = await client.getPaymentInfo(token);
48
+ console.log(info.totalPayment, info.currency, info.payment_type);
49
+
50
+ // When user submits the form, complete payment and show PayTR iframe
51
+ const { iframeToken } = await client.completePayment({
52
+ token,
53
+ userName: "John Doe",
54
+ userAddress: "Istanbul, Turkey",
55
+ userPhone: "+905551234567",
56
+ });
57
+ // Use iframeToken in the PayTR iframe as per PayTR docs.
58
+ ```
59
+
60
+ ### Checkout URL helper
61
+
62
+ ```ts
63
+ client.getCheckoutUrl(token); // Turkish checkout: .../tr?token=...
64
+ client.getCheckoutUrl(token, "en"); // English: .../en?token=...
65
+ ```
66
+
67
+ ## API reference
68
+
69
+ | Method | Description |
70
+ |--------|-------------|
71
+ | `createSession(params, options?)` | Create a payment session. Requires API key. Returns `{ token }`. |
72
+ | `getPaymentInfo(token)` | Get payment/session info by token. Returns `PaymentInfo`. |
73
+ | `getCheckoutUrl(token, locale?)` | Build checkout page URL (`"tr"` or `"en"`, default `"tr"`). |
74
+ | `completePayment(params)` | Submit customer details. Returns `{ iframeToken }` for PayTR iframe. |
75
+
76
+ Types: `CreateSessionParams`, `CreateSessionResponse`, `PaymentInfo`, `CompletePaymentParams`, `CompletePaymentResponse`, `PaymentClientConfig`. See TypeScript definitions.
77
+
78
+ ## Errors
79
+
80
+ On 4xx/5xx or network failure, the client throws `PaymentClientError`:
81
+
82
+ - `message`: Human-readable message (or server `error` field when JSON).
83
+ - `status`: HTTP status code (optional).
84
+ - `body`: Raw response body (optional).
85
+
86
+ ```ts
87
+ import { PaymentClient, PaymentClientError } from "horizon-pay";
88
+
89
+ try {
90
+ await client.createSession({ ... });
91
+ } catch (err) {
92
+ if (err instanceof PaymentClientError) {
93
+ console.error(err.status, err.message, err.body);
94
+ }
95
+ throw err;
96
+ }
97
+ ```
98
+
99
+ ## License
100
+
101
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,147 @@
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
+ PaymentClient: () => PaymentClient,
24
+ PaymentClientError: () => PaymentClientError
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/errors.ts
29
+ var PaymentClientError = class _PaymentClientError extends Error {
30
+ constructor(message, status, code, body) {
31
+ super(message);
32
+ this.status = status;
33
+ this.code = code;
34
+ this.body = body;
35
+ this.name = "PaymentClientError";
36
+ Object.setPrototypeOf(this, _PaymentClientError.prototype);
37
+ }
38
+ };
39
+
40
+ // src/client.ts
41
+ var PaymentClient = class {
42
+ baseUrl;
43
+ apiKey;
44
+ constructor(config) {
45
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
46
+ this.apiKey = config.apiKey;
47
+ }
48
+ /**
49
+ * Create a payment session. Requires API key (constructor or passed here).
50
+ * Returns a token to use in checkout URL and getPaymentInfo/completePayment.
51
+ */
52
+ async createSession(params, options) {
53
+ const apiKey = options?.apiKey ?? this.apiKey;
54
+ if (!apiKey) {
55
+ throw new PaymentClientError(
56
+ "API key is required for createSession. Pass it in PaymentClient config or createSession options."
57
+ );
58
+ }
59
+ const body = {
60
+ amount: params.amount,
61
+ currency: params.currency ?? "TL",
62
+ payer_email: params.payerEmail,
63
+ payment_type: params.paymentType ?? "one_time",
64
+ metadata: params.metadata ?? {},
65
+ success_redirect_url: params.successRedirectUrl,
66
+ fail_redirect_url: params.failRedirectUrl,
67
+ webhook_url: params.webhookUrl
68
+ };
69
+ const res = await this.request("/payment/sessions", {
70
+ method: "POST",
71
+ headers: {
72
+ "Content-Type": "application/json",
73
+ "X-API-Key": apiKey
74
+ },
75
+ body: JSON.stringify(body)
76
+ });
77
+ return res;
78
+ }
79
+ /**
80
+ * Get payment/session info by token (for checkout UI).
81
+ */
82
+ async getPaymentInfo(token) {
83
+ const res = await this.request(
84
+ `/payment/sessions?token=${encodeURIComponent(token)}`,
85
+ { method: "GET" }
86
+ );
87
+ return res;
88
+ }
89
+ /**
90
+ * Build checkout page URL for the given token and locale.
91
+ * @param token - Session token from createSession
92
+ * @param locale - "tr" or "en" (default "tr")
93
+ */
94
+ getCheckoutUrl(token, locale = "tr") {
95
+ const path = locale === "en" ? "en" : "tr";
96
+ return `${this.baseUrl}/${path}?token=${encodeURIComponent(token)}`;
97
+ }
98
+ /**
99
+ * Submit customer details and get PayTR iframe token.
100
+ * Use the returned iframeToken in the PayTR iframe to complete the payment.
101
+ */
102
+ async completePayment(params) {
103
+ const body = {
104
+ token: params.token,
105
+ user_name: params.userName,
106
+ user_address: params.userAddress,
107
+ user_phone: params.userPhone
108
+ };
109
+ const res = await this.request("/payment/complete-payment", {
110
+ method: "POST",
111
+ headers: { "Content-Type": "application/json" },
112
+ body: JSON.stringify(body)
113
+ });
114
+ return res;
115
+ }
116
+ async request(path, init) {
117
+ const url = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
118
+ let res;
119
+ try {
120
+ res = await fetch(url, init);
121
+ } catch (err) {
122
+ const message = err instanceof Error ? err.message : String(err);
123
+ throw new PaymentClientError(`Network error: ${message}`);
124
+ }
125
+ const text = await res.text();
126
+ let body = null;
127
+ if (text) {
128
+ try {
129
+ body = JSON.parse(text);
130
+ } catch {
131
+ body = text;
132
+ }
133
+ }
134
+ if (!res.ok) {
135
+ const errBody = body;
136
+ const message = (errBody?.error && typeof errBody.error === "string" ? errBody.error : res.statusText) || `Request failed with status ${res.status}`;
137
+ throw new PaymentClientError(message, res.status, void 0, body);
138
+ }
139
+ return body ?? {};
140
+ }
141
+ };
142
+ // Annotate the CommonJS export names for ESM import in node:
143
+ 0 && (module.exports = {
144
+ PaymentClient,
145
+ PaymentClientError
146
+ });
147
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export { PaymentClient } from \"./client.js\";\nexport type {\n CreateSessionParams,\n CreateSessionResponse,\n PaymentInfo,\n CompletePaymentParams,\n CompletePaymentResponse,\n PaymentClientConfig,\n} from \"./types.js\";\nexport { PaymentClientError } from \"./errors.js\";\n","/**\n * Thrown when a payment API request fails (4xx/5xx or network error).\n */\nexport class PaymentClientError extends Error {\n constructor(\n message: string,\n public readonly status?: number,\n public readonly code?: string,\n public readonly body?: unknown\n ) {\n super(message);\n this.name = \"PaymentClientError\";\n Object.setPrototypeOf(this, PaymentClientError.prototype);\n }\n}\n","import { PaymentClientError } from \"./errors.js\";\nimport type {\n PaymentClientConfig,\n CreateSessionParams,\n CreateSessionResponse,\n PaymentInfo,\n CompletePaymentParams,\n CompletePaymentResponse,\n ApiErrorBody,\n} from \"./types.js\";\n\n/**\n * Client for the Horizon Zeta Payment API.\n * Use createSession (with API key), getPaymentInfo, getCheckoutUrl, and completePayment.\n */\nexport class PaymentClient {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n\n constructor(config: PaymentClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n this.apiKey = config.apiKey;\n }\n\n /**\n * Create a payment session. Requires API key (constructor or passed here).\n * Returns a token to use in checkout URL and getPaymentInfo/completePayment.\n */\n async createSession(\n params: CreateSessionParams,\n options?: { apiKey?: string }\n ): Promise<CreateSessionResponse> {\n const apiKey = options?.apiKey ?? this.apiKey;\n if (!apiKey) {\n throw new PaymentClientError(\n \"API key is required for createSession. Pass it in PaymentClient config or createSession options.\"\n );\n }\n const body = {\n amount: params.amount,\n currency: params.currency ?? \"TL\",\n payer_email: params.payerEmail,\n payment_type: params.paymentType ?? \"one_time\",\n metadata: params.metadata ?? {},\n success_redirect_url: params.successRedirectUrl,\n fail_redirect_url: params.failRedirectUrl,\n webhook_url: params.webhookUrl,\n };\n const res = await this.request(\"/payment/sessions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": apiKey,\n },\n body: JSON.stringify(body),\n });\n return res as unknown as CreateSessionResponse;\n }\n\n /**\n * Get payment/session info by token (for checkout UI).\n */\n async getPaymentInfo(token: string): Promise<PaymentInfo> {\n const res = await this.request(\n `/payment/sessions?token=${encodeURIComponent(token)}`,\n { method: \"GET\" }\n );\n return res as unknown as PaymentInfo;\n }\n\n /**\n * Build checkout page URL for the given token and locale.\n * @param token - Session token from createSession\n * @param locale - \"tr\" or \"en\" (default \"tr\")\n */\n getCheckoutUrl(token: string, locale: \"tr\" | \"en\" = \"tr\"): string {\n const path = locale === \"en\" ? \"en\" : \"tr\";\n return `${this.baseUrl}/${path}?token=${encodeURIComponent(token)}`;\n }\n\n /**\n * Submit customer details and get PayTR iframe token.\n * Use the returned iframeToken in the PayTR iframe to complete the payment.\n */\n async completePayment(params: CompletePaymentParams): Promise<CompletePaymentResponse> {\n const body = {\n token: params.token,\n user_name: params.userName,\n user_address: params.userAddress,\n user_phone: params.userPhone,\n };\n const res = await this.request(\"/payment/complete-payment\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return res as unknown as CompletePaymentResponse;\n }\n\n private async request(\n path: string,\n init: RequestInit\n ): Promise<Record<string, unknown>> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n let res: Response;\n try {\n res = await fetch(url, init);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new PaymentClientError(`Network error: ${message}`);\n }\n const text = await res.text();\n let body: unknown = null;\n if (text) {\n try {\n body = JSON.parse(text) as Record<string, unknown>;\n } catch {\n body = text;\n }\n }\n if (!res.ok) {\n const errBody = body as ApiErrorBody | undefined;\n const message =\n (errBody?.error && typeof errBody.error === \"string\"\n ? errBody.error\n : res.statusText) || `Request failed with status ${res.status}`;\n throw new PaymentClientError(message, res.status, undefined, body);\n }\n return (body ?? {}) as Record<string, unknown>;\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Configuration for the payment API client.
3
+ */
4
+ interface PaymentClientConfig {
5
+ /** Base URL of the payment service (e.g. https://pay.horizonzeta.com) */
6
+ baseUrl: string;
7
+ /** API key for createSession (required when calling createSession) */
8
+ apiKey?: string;
9
+ }
10
+ /**
11
+ * Parameters for creating a payment session.
12
+ */
13
+ interface CreateSessionParams {
14
+ /** Payment amount (e.g. in TL) */
15
+ amount: number;
16
+ /** Payer email address */
17
+ payerEmail: string;
18
+ /** Currency code (default "TL") */
19
+ currency?: string;
20
+ /** "one_time" or "subscription" */
21
+ paymentType?: "one_time" | "subscription";
22
+ /** Optional metadata (discount, plan, users, etc.) */
23
+ metadata?: Record<string, unknown>;
24
+ /** URL to redirect after successful payment */
25
+ successRedirectUrl?: string;
26
+ /** URL to redirect after failed payment */
27
+ failRedirectUrl?: string;
28
+ /** Webhook URL for payment completion notification */
29
+ webhookUrl?: string;
30
+ }
31
+ /**
32
+ * Response from createSession.
33
+ */
34
+ interface CreateSessionResponse {
35
+ /** Token to use in checkout URL and subsequent calls */
36
+ token: string;
37
+ }
38
+ /**
39
+ * Payment/session info returned by getPaymentInfo.
40
+ */
41
+ interface PaymentInfo {
42
+ totalPayment: number;
43
+ discount: number;
44
+ upgradeDisc: number;
45
+ users: unknown[];
46
+ plan: unknown | null;
47
+ productDetailText: unknown | null;
48
+ currency: string;
49
+ payment_type: string;
50
+ }
51
+ /**
52
+ * Parameters for completing payment (customer details + session token).
53
+ */
54
+ interface CompletePaymentParams {
55
+ /** Session token from createSession */
56
+ token: string;
57
+ userName: string;
58
+ userAddress: string;
59
+ userPhone: string;
60
+ }
61
+ /**
62
+ * Response from completePayment (PayTR iframe token).
63
+ */
64
+ interface CompletePaymentResponse {
65
+ iframeToken: string;
66
+ }
67
+
68
+ /**
69
+ * Client for the Horizon Zeta Payment API.
70
+ * Use createSession (with API key), getPaymentInfo, getCheckoutUrl, and completePayment.
71
+ */
72
+ declare class PaymentClient {
73
+ private readonly baseUrl;
74
+ private readonly apiKey?;
75
+ constructor(config: PaymentClientConfig);
76
+ /**
77
+ * Create a payment session. Requires API key (constructor or passed here).
78
+ * Returns a token to use in checkout URL and getPaymentInfo/completePayment.
79
+ */
80
+ createSession(params: CreateSessionParams, options?: {
81
+ apiKey?: string;
82
+ }): Promise<CreateSessionResponse>;
83
+ /**
84
+ * Get payment/session info by token (for checkout UI).
85
+ */
86
+ getPaymentInfo(token: string): Promise<PaymentInfo>;
87
+ /**
88
+ * Build checkout page URL for the given token and locale.
89
+ * @param token - Session token from createSession
90
+ * @param locale - "tr" or "en" (default "tr")
91
+ */
92
+ getCheckoutUrl(token: string, locale?: "tr" | "en"): string;
93
+ /**
94
+ * Submit customer details and get PayTR iframe token.
95
+ * Use the returned iframeToken in the PayTR iframe to complete the payment.
96
+ */
97
+ completePayment(params: CompletePaymentParams): Promise<CompletePaymentResponse>;
98
+ private request;
99
+ }
100
+
101
+ /**
102
+ * Thrown when a payment API request fails (4xx/5xx or network error).
103
+ */
104
+ declare class PaymentClientError extends Error {
105
+ readonly status?: number | undefined;
106
+ readonly code?: string | undefined;
107
+ readonly body?: unknown | undefined;
108
+ constructor(message: string, status?: number | undefined, code?: string | undefined, body?: unknown | undefined);
109
+ }
110
+
111
+ export { type CompletePaymentParams, type CompletePaymentResponse, type CreateSessionParams, type CreateSessionResponse, PaymentClient, type PaymentClientConfig, PaymentClientError, type PaymentInfo };
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Configuration for the payment API client.
3
+ */
4
+ interface PaymentClientConfig {
5
+ /** Base URL of the payment service (e.g. https://pay.horizonzeta.com) */
6
+ baseUrl: string;
7
+ /** API key for createSession (required when calling createSession) */
8
+ apiKey?: string;
9
+ }
10
+ /**
11
+ * Parameters for creating a payment session.
12
+ */
13
+ interface CreateSessionParams {
14
+ /** Payment amount (e.g. in TL) */
15
+ amount: number;
16
+ /** Payer email address */
17
+ payerEmail: string;
18
+ /** Currency code (default "TL") */
19
+ currency?: string;
20
+ /** "one_time" or "subscription" */
21
+ paymentType?: "one_time" | "subscription";
22
+ /** Optional metadata (discount, plan, users, etc.) */
23
+ metadata?: Record<string, unknown>;
24
+ /** URL to redirect after successful payment */
25
+ successRedirectUrl?: string;
26
+ /** URL to redirect after failed payment */
27
+ failRedirectUrl?: string;
28
+ /** Webhook URL for payment completion notification */
29
+ webhookUrl?: string;
30
+ }
31
+ /**
32
+ * Response from createSession.
33
+ */
34
+ interface CreateSessionResponse {
35
+ /** Token to use in checkout URL and subsequent calls */
36
+ token: string;
37
+ }
38
+ /**
39
+ * Payment/session info returned by getPaymentInfo.
40
+ */
41
+ interface PaymentInfo {
42
+ totalPayment: number;
43
+ discount: number;
44
+ upgradeDisc: number;
45
+ users: unknown[];
46
+ plan: unknown | null;
47
+ productDetailText: unknown | null;
48
+ currency: string;
49
+ payment_type: string;
50
+ }
51
+ /**
52
+ * Parameters for completing payment (customer details + session token).
53
+ */
54
+ interface CompletePaymentParams {
55
+ /** Session token from createSession */
56
+ token: string;
57
+ userName: string;
58
+ userAddress: string;
59
+ userPhone: string;
60
+ }
61
+ /**
62
+ * Response from completePayment (PayTR iframe token).
63
+ */
64
+ interface CompletePaymentResponse {
65
+ iframeToken: string;
66
+ }
67
+
68
+ /**
69
+ * Client for the Horizon Zeta Payment API.
70
+ * Use createSession (with API key), getPaymentInfo, getCheckoutUrl, and completePayment.
71
+ */
72
+ declare class PaymentClient {
73
+ private readonly baseUrl;
74
+ private readonly apiKey?;
75
+ constructor(config: PaymentClientConfig);
76
+ /**
77
+ * Create a payment session. Requires API key (constructor or passed here).
78
+ * Returns a token to use in checkout URL and getPaymentInfo/completePayment.
79
+ */
80
+ createSession(params: CreateSessionParams, options?: {
81
+ apiKey?: string;
82
+ }): Promise<CreateSessionResponse>;
83
+ /**
84
+ * Get payment/session info by token (for checkout UI).
85
+ */
86
+ getPaymentInfo(token: string): Promise<PaymentInfo>;
87
+ /**
88
+ * Build checkout page URL for the given token and locale.
89
+ * @param token - Session token from createSession
90
+ * @param locale - "tr" or "en" (default "tr")
91
+ */
92
+ getCheckoutUrl(token: string, locale?: "tr" | "en"): string;
93
+ /**
94
+ * Submit customer details and get PayTR iframe token.
95
+ * Use the returned iframeToken in the PayTR iframe to complete the payment.
96
+ */
97
+ completePayment(params: CompletePaymentParams): Promise<CompletePaymentResponse>;
98
+ private request;
99
+ }
100
+
101
+ /**
102
+ * Thrown when a payment API request fails (4xx/5xx or network error).
103
+ */
104
+ declare class PaymentClientError extends Error {
105
+ readonly status?: number | undefined;
106
+ readonly code?: string | undefined;
107
+ readonly body?: unknown | undefined;
108
+ constructor(message: string, status?: number | undefined, code?: string | undefined, body?: unknown | undefined);
109
+ }
110
+
111
+ export { type CompletePaymentParams, type CompletePaymentResponse, type CreateSessionParams, type CreateSessionResponse, PaymentClient, type PaymentClientConfig, PaymentClientError, type PaymentInfo };
package/dist/index.js ADDED
@@ -0,0 +1,119 @@
1
+ // src/errors.ts
2
+ var PaymentClientError = class _PaymentClientError extends Error {
3
+ constructor(message, status, code, body) {
4
+ super(message);
5
+ this.status = status;
6
+ this.code = code;
7
+ this.body = body;
8
+ this.name = "PaymentClientError";
9
+ Object.setPrototypeOf(this, _PaymentClientError.prototype);
10
+ }
11
+ };
12
+
13
+ // src/client.ts
14
+ var PaymentClient = class {
15
+ baseUrl;
16
+ apiKey;
17
+ constructor(config) {
18
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
19
+ this.apiKey = config.apiKey;
20
+ }
21
+ /**
22
+ * Create a payment session. Requires API key (constructor or passed here).
23
+ * Returns a token to use in checkout URL and getPaymentInfo/completePayment.
24
+ */
25
+ async createSession(params, options) {
26
+ const apiKey = options?.apiKey ?? this.apiKey;
27
+ if (!apiKey) {
28
+ throw new PaymentClientError(
29
+ "API key is required for createSession. Pass it in PaymentClient config or createSession options."
30
+ );
31
+ }
32
+ const body = {
33
+ amount: params.amount,
34
+ currency: params.currency ?? "TL",
35
+ payer_email: params.payerEmail,
36
+ payment_type: params.paymentType ?? "one_time",
37
+ metadata: params.metadata ?? {},
38
+ success_redirect_url: params.successRedirectUrl,
39
+ fail_redirect_url: params.failRedirectUrl,
40
+ webhook_url: params.webhookUrl
41
+ };
42
+ const res = await this.request("/payment/sessions", {
43
+ method: "POST",
44
+ headers: {
45
+ "Content-Type": "application/json",
46
+ "X-API-Key": apiKey
47
+ },
48
+ body: JSON.stringify(body)
49
+ });
50
+ return res;
51
+ }
52
+ /**
53
+ * Get payment/session info by token (for checkout UI).
54
+ */
55
+ async getPaymentInfo(token) {
56
+ const res = await this.request(
57
+ `/payment/sessions?token=${encodeURIComponent(token)}`,
58
+ { method: "GET" }
59
+ );
60
+ return res;
61
+ }
62
+ /**
63
+ * Build checkout page URL for the given token and locale.
64
+ * @param token - Session token from createSession
65
+ * @param locale - "tr" or "en" (default "tr")
66
+ */
67
+ getCheckoutUrl(token, locale = "tr") {
68
+ const path = locale === "en" ? "en" : "tr";
69
+ return `${this.baseUrl}/${path}?token=${encodeURIComponent(token)}`;
70
+ }
71
+ /**
72
+ * Submit customer details and get PayTR iframe token.
73
+ * Use the returned iframeToken in the PayTR iframe to complete the payment.
74
+ */
75
+ async completePayment(params) {
76
+ const body = {
77
+ token: params.token,
78
+ user_name: params.userName,
79
+ user_address: params.userAddress,
80
+ user_phone: params.userPhone
81
+ };
82
+ const res = await this.request("/payment/complete-payment", {
83
+ method: "POST",
84
+ headers: { "Content-Type": "application/json" },
85
+ body: JSON.stringify(body)
86
+ });
87
+ return res;
88
+ }
89
+ async request(path, init) {
90
+ const url = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
91
+ let res;
92
+ try {
93
+ res = await fetch(url, init);
94
+ } catch (err) {
95
+ const message = err instanceof Error ? err.message : String(err);
96
+ throw new PaymentClientError(`Network error: ${message}`);
97
+ }
98
+ const text = await res.text();
99
+ let body = null;
100
+ if (text) {
101
+ try {
102
+ body = JSON.parse(text);
103
+ } catch {
104
+ body = text;
105
+ }
106
+ }
107
+ if (!res.ok) {
108
+ const errBody = body;
109
+ const message = (errBody?.error && typeof errBody.error === "string" ? errBody.error : res.statusText) || `Request failed with status ${res.status}`;
110
+ throw new PaymentClientError(message, res.status, void 0, body);
111
+ }
112
+ return body ?? {};
113
+ }
114
+ };
115
+ export {
116
+ PaymentClient,
117
+ PaymentClientError
118
+ };
119
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["/**\n * Thrown when a payment API request fails (4xx/5xx or network error).\n */\nexport class PaymentClientError extends Error {\n constructor(\n message: string,\n public readonly status?: number,\n public readonly code?: string,\n public readonly body?: unknown\n ) {\n super(message);\n this.name = \"PaymentClientError\";\n Object.setPrototypeOf(this, PaymentClientError.prototype);\n }\n}\n","import { PaymentClientError } from \"./errors.js\";\nimport type {\n PaymentClientConfig,\n CreateSessionParams,\n CreateSessionResponse,\n PaymentInfo,\n CompletePaymentParams,\n CompletePaymentResponse,\n ApiErrorBody,\n} from \"./types.js\";\n\n/**\n * Client for the Horizon Zeta Payment API.\n * Use createSession (with API key), getPaymentInfo, getCheckoutUrl, and completePayment.\n */\nexport class PaymentClient {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n\n constructor(config: PaymentClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n this.apiKey = config.apiKey;\n }\n\n /**\n * Create a payment session. Requires API key (constructor or passed here).\n * Returns a token to use in checkout URL and getPaymentInfo/completePayment.\n */\n async createSession(\n params: CreateSessionParams,\n options?: { apiKey?: string }\n ): Promise<CreateSessionResponse> {\n const apiKey = options?.apiKey ?? this.apiKey;\n if (!apiKey) {\n throw new PaymentClientError(\n \"API key is required for createSession. Pass it in PaymentClient config or createSession options.\"\n );\n }\n const body = {\n amount: params.amount,\n currency: params.currency ?? \"TL\",\n payer_email: params.payerEmail,\n payment_type: params.paymentType ?? \"one_time\",\n metadata: params.metadata ?? {},\n success_redirect_url: params.successRedirectUrl,\n fail_redirect_url: params.failRedirectUrl,\n webhook_url: params.webhookUrl,\n };\n const res = await this.request(\"/payment/sessions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-API-Key\": apiKey,\n },\n body: JSON.stringify(body),\n });\n return res as unknown as CreateSessionResponse;\n }\n\n /**\n * Get payment/session info by token (for checkout UI).\n */\n async getPaymentInfo(token: string): Promise<PaymentInfo> {\n const res = await this.request(\n `/payment/sessions?token=${encodeURIComponent(token)}`,\n { method: \"GET\" }\n );\n return res as unknown as PaymentInfo;\n }\n\n /**\n * Build checkout page URL for the given token and locale.\n * @param token - Session token from createSession\n * @param locale - \"tr\" or \"en\" (default \"tr\")\n */\n getCheckoutUrl(token: string, locale: \"tr\" | \"en\" = \"tr\"): string {\n const path = locale === \"en\" ? \"en\" : \"tr\";\n return `${this.baseUrl}/${path}?token=${encodeURIComponent(token)}`;\n }\n\n /**\n * Submit customer details and get PayTR iframe token.\n * Use the returned iframeToken in the PayTR iframe to complete the payment.\n */\n async completePayment(params: CompletePaymentParams): Promise<CompletePaymentResponse> {\n const body = {\n token: params.token,\n user_name: params.userName,\n user_address: params.userAddress,\n user_phone: params.userPhone,\n };\n const res = await this.request(\"/payment/complete-payment\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return res as unknown as CompletePaymentResponse;\n }\n\n private async request(\n path: string,\n init: RequestInit\n ): Promise<Record<string, unknown>> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n let res: Response;\n try {\n res = await fetch(url, init);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new PaymentClientError(`Network error: ${message}`);\n }\n const text = await res.text();\n let body: unknown = null;\n if (text) {\n try {\n body = JSON.parse(text) as Record<string, unknown>;\n } catch {\n body = text;\n }\n }\n if (!res.ok) {\n const errBody = body as ApiErrorBody | undefined;\n const message =\n (errBody?.error && typeof errBody.error === \"string\"\n ? errBody.error\n : res.statusText) || `Request failed with status ${res.status}`;\n throw new PaymentClientError(message, res.status, undefined, body);\n }\n return (body ?? {}) as Record<string, unknown>;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@kerembay9/horizon-pay",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript client for Horizon Zeta Payment API",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": ["dist"],
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "devDependencies": {
22
+ "tsup": "^8.3.5",
23
+ "typescript": "^5.6.3"
24
+ },
25
+ "engines": {
26
+ "node": ">=18"
27
+ }
28
+ }