@bitpal/checkout 0.5.0 → 0.6.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 CHANGED
@@ -11,25 +11,27 @@ pnpm add @bitpal/checkout
11
11
  # npm i @bitpal/checkout / yarn add @bitpal/checkout
12
12
  ```
13
13
 
14
- ## ⚠️ Amount format (read this first)
14
+ ## Amounts — just pass a human number
15
15
 
16
- USDC / USDT have **6 decimals**. All amounts are **atomic μUSDC integer strings** — never floats.
16
+ Use **`amount`** in line items — a plain USD string like `"20"`, `"0.5"`, `"29.00"`. No decimals to compute.
17
17
 
18
- ```
19
- $1.00 → "1000000"
20
- $29.00 → "29000000"
21
- $0.50 → "500000"
18
+ ```ts
19
+ line_items: [{ name: 'Pro', amount: '29', currency: 'USDC' }]
22
20
  ```
23
21
 
24
- Passing a decimal string like `"29.00"` returns **400**. Use the helpers:
22
+ **The amount is a USD price — it does NOT depend on the chain or token decimals.** Whether the buyer pays with USDC (6dp) on Base or USDT (18dp) on BNB, you pass the same `amount`. BitPal rescales to the buyer's chosen token at deposit time. So you never compute per-token decimals. (Prices via `prices.create` take the same `amount`.)
25
23
 
26
- ```ts
27
- import { toAtomicUSDC, fromAtomicUSDC } from '@bitpal/checkout';
24
+ <details><summary>Advanced: raw atomic amounts</summary>
28
25
 
29
- toAtomicUSDC('29.00'); // → "29000000"
30
- fromAtomicUSDC('29000000'); // → "29.00"
26
+ If you already hold **atomic μUSD integer strings** ($1 = `"1000000"`), pass `amount_atomic` instead (mutually exclusive with `amount`):
27
+
28
+ ```
29
+ $1.00 → "1000000" $29.00 → "29000000" $0.50 → "500000"
31
30
  ```
32
31
 
32
+ Helpers for atomic conversion (e.g. reading `amount_total` back): `toAtomic(v, decimals)` / `fromAtomic(v, decimals)` — read `decimals` from `payment_options[]`/`token_decimals` (6 for USDC/USDT, 18 for BNB USDT). `toAtomicUSDC`/`fromAtomicUSDC` are 6dp shortcuts.
33
+ </details>
34
+
33
35
  ## Environments
34
36
 
35
37
  API keys are environment-scoped:
@@ -45,8 +47,8 @@ there is no separate flag.
45
47
  ### Setup
46
48
 
47
49
  ```ts
48
- // helpers (toAtomicUSDC / fromAtomicUSDC) are used in the snippets below
49
- import { BitPal, toAtomicUSDC, fromAtomicUSDC } from '@bitpal/checkout';
50
+ import { BitPal } from '@bitpal/checkout';
51
+ // (optional atomic helpers if you need them: import { toAtomic, fromAtomic } from '@bitpal/checkout')
50
52
 
51
53
  const bitpal = new BitPal(process.env.BITPAL_API_KEY!); // bp_test_... / bp_live_...
52
54
  ```
@@ -61,7 +63,7 @@ shows the per-order deposit address + QR, and confirms the payment on-chain.
61
63
  ```ts
62
64
  const { data: session } = await bitpal.checkout.createSession({
63
65
  line_items: [
64
- { name: 'Pro Plan', amount: toAtomicUSDC('29.00'), currency: 'USDC' },
66
+ { name: 'Pro Plan', amount: '29', currency: 'USDC' }, // just the USD number
65
67
  ],
66
68
  pay_chain: 'eip155:84532', // Base Sepolia (test mode). Live mode: 'eip155:8453' (Base mainnet).
67
69
  // Or use allowed_pay_chains for a buyer-picked chain.
@@ -85,7 +87,7 @@ you.
85
87
  ```ts
86
88
  const { data } = await bitpal.checkout.issueDepositAddress(session.id, {
87
89
  session_token: session.session_token!, // from createSession
88
- refundAddress: '0xBuyerWallet...', // committed to the address, immutable after issuance
90
+ refundAddress: '0xBuyerWallet...', // VM-matched (EVM 0x… / Tron T… / Solana base58); committed, immutable after issuance
89
91
  chain: 'eip155:84532', // match the session's chain (test: Base Sepolia / live: eip155:8453).
90
92
  // only needed for multi-option (allowed_pay_chains) sessions
91
93
  token: 'USDC',
@@ -195,10 +197,9 @@ new BitPal({ apiKey, baseUrl: 'https://…' }); // config object — override ba
195
197
 
196
198
  ## Runnable examples
197
199
 
198
- The [source repo](https://github.com/superlabs-x/bitpal-checkout-sdk)'s `examples/` directory
199
- has runnable references (not shipped in the npm package): `create-session.mjs`,
200
- `webhook-receiver.mjs`, and a `full-integration/` Express store wiring session creation +
201
- webhook verification + idempotency.
200
+ The source repo's `examples/` directory has runnable references (not shipped in the npm
201
+ package): `create-session.mjs`, `webhook-receiver.mjs`, and a `full-integration/` Express
202
+ store wiring session creation + webhook verification + idempotency.
202
203
 
203
204
  ## Build
204
205
 
@@ -213,7 +214,7 @@ pnpm build # tsup → dist/ (ESM + .d.ts)
213
214
  `verifyWebhookSignature(rawBody, sigHeader, secret, { timestamp: tsHeader })`. A 3-argument call now
214
215
  returns `false`. The signed content changed from `body` to `` `${timestamp}.${body}` ``.
215
216
  - Deduplicate on the signed `event.id`, not the `X-Webhook-Id` header.
216
- - Removed legacy pre-release methods (`payWithAuthorization`, `submitExternalPayment`) and escrow refund helpers —
217
+ - Removed 안1 methods (`payWithAuthorization`, `submitExternalPayment`) and escrow refund helpers —
217
218
  checkout is non-custodial deposit-address (see Usage above).
218
219
 
219
220
  ## License
package/dist/index.cjs CHANGED
@@ -34,11 +34,14 @@ __export(index_exports, {
34
34
  BitPalCheckoutClient: () => BitPalCheckoutClient,
35
35
  BitPalError: () => BitPalError,
36
36
  CHECKOUT_WEBHOOK_EVENTS: () => CHECKOUT_WEBHOOK_EVENTS,
37
+ PaymentLinksResource: () => PaymentLinksResource,
37
38
  PricesResource: () => PricesResource,
38
39
  ProductsResource: () => ProductsResource,
39
40
  WEBHOOK_HEADERS: () => WEBHOOK_HEADERS,
41
+ fromAtomic: () => fromAtomic,
40
42
  fromAtomicUSDC: () => fromAtomicUSDC,
41
43
  parseWebhookEvent: () => parseWebhookEvent,
44
+ toAtomic: () => toAtomic,
42
45
  toAtomicUSDC: () => toAtomicUSDC,
43
46
  verifyWebhookSignature: () => verifyWebhookSignature
44
47
  });
@@ -101,8 +104,39 @@ var PricesResource = class {
101
104
  return this.request("PATCH", `/v1/checkout/prices/${encodeURIComponent(priceId)}`, params);
102
105
  }
103
106
  };
107
+ var PaymentLinksResource = class {
108
+ constructor(request) {
109
+ this.request = request;
110
+ }
111
+ request;
112
+ /** POST /v1/checkout/payment-links */
113
+ create(params) {
114
+ return this.request("POST", "/v1/checkout/payment-links", params);
115
+ }
116
+ /** GET /v1/checkout/payment-links */
117
+ list(params) {
118
+ return this.request("GET", `/v1/checkout/payment-links${toQuery(params)}`);
119
+ }
120
+ /** GET /v1/checkout/payment-links/:id */
121
+ retrieve(linkId) {
122
+ return this.request("GET", `/v1/checkout/payment-links/${encodeURIComponent(linkId)}`);
123
+ }
124
+ /** PATCH /v1/checkout/payment-links/:id */
125
+ update(linkId, params) {
126
+ return this.request("PATCH", `/v1/checkout/payment-links/${encodeURIComponent(linkId)}`, params);
127
+ }
128
+ };
104
129
 
105
130
  // src/client.ts
131
+ function validateLineItem(li) {
132
+ if ("price_id" in li) return li;
133
+ const hasHuman = li.amount != null;
134
+ const hasAtomic = li.amount_atomic != null;
135
+ if (hasHuman === hasAtomic) {
136
+ throw new Error('[BitPal] line item requires exactly one of `amount` (USD number, e.g. "29") or `amount_atomic` (raw \u03BCUSD integer, e.g. "29000000").');
137
+ }
138
+ return li;
139
+ }
106
140
  var DEFAULT_BASE_URL = "https://api.bitpal.io";
107
141
  var DEFAULT_TIMEOUT = 3e4;
108
142
  var BitPalCheckoutClient = class {
@@ -114,6 +148,8 @@ var BitPalCheckoutClient = class {
114
148
  products;
115
149
  /** PROD-LINK-3a-SDK: immutable Price 관리 — 가격 변경은 비활성화 + 새 price 생성 */
116
150
  prices;
151
+ /** PROD-LINK-4-SDK: Payment Link 관리 — 대시보드 없이 코드로 결제 링크 생성 (server-side 전용) */
152
+ paymentLinks;
117
153
  constructor(config) {
118
154
  this.apiKey = config.apiKey;
119
155
  this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
@@ -121,6 +157,7 @@ var BitPalCheckoutClient = class {
121
157
  const requester = (method, path, body) => this.request(method, path, body);
122
158
  this.products = new ProductsResource(requester);
123
159
  this.prices = new PricesResource(requester);
160
+ this.paymentLinks = new PaymentLinksResource(requester);
124
161
  }
125
162
  /* ─── 내부 HTTP ─── */
126
163
  async request(method, path, body, extraHeaders) {
@@ -153,20 +190,22 @@ var BitPalCheckoutClient = class {
153
190
  /**
154
191
  * 체크아웃 세션 생성.
155
192
  *
156
- * 모든 `line_items[].amount`는 atomic μUSDC 정수 문자열이어야 한다 ($1 = "1000000").
157
- * decimal 표기는 거부된다 — `toAtomicUSDC()` 헬퍼 사용 권장.
193
+ * `line_items[].amount` 는 사람 표기 USD 문자열("29", "0.5") — decimal 계산 불필요.
194
+ * 이미 raw μUSD 정수라면 `amount_atomic`("29000000") 사용(고급). 둘은 상호 배타.
158
195
  *
159
196
  * @example
160
- * import { BitPal, toAtomicUSDC } from '@bitpal/checkout';
197
+ * import { BitPal } from '@bitpal/checkout';
161
198
  * const bp = new BitPal('bp_test_...');
162
199
  * const { data } = await bp.checkout.createSession({
163
- * line_items: [{ name: 'Pro', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
200
+ * // amount: 사람 표기 USD("29", "0.5"). 금액은 USD 가격이라 체인/토큰 decimal 무관.
201
+ * line_items: [{ name: 'Pro', amount: '29', currency: 'USDC' }],
164
202
  * });
165
203
  * console.log(data.url); // → buyer를 redirect할 결제 페이지
166
204
  *
167
205
  * // 멀티체인 허용 — 구매자가 Base/Optimism 중 선택(하나뿐이면 자동 선택):
206
+ * // 어떤 체인·토큰이든 amount 그대로 — 서버가 발급 시 토큰 decimals 로 재스케일.
168
207
  * await bp.checkout.createSession({
169
- * line_items: [{ name: 'Pro', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
208
+ * line_items: [{ name: 'Pro', amount: '29', currency: 'USDC' }],
170
209
  * allowed_pay_chains: ['eip155:84532', 'eip155:11155420'],
171
210
  * });
172
211
  * // 단일 체인 고정은 pay_chain 사용(둘은 상호 배타).
@@ -175,10 +214,11 @@ var BitPalCheckoutClient = class {
175
214
  if (params.pay_chain && params.allowed_pay_chains && params.allowed_pay_chains.length > 0) {
176
215
  throw new Error("[BitPal] pay_chain and allowed_pay_chains are mutually exclusive \u2014 use only one.");
177
216
  }
217
+ const body = { ...params, line_items: params.line_items.map(validateLineItem) };
178
218
  const res = await this.request(
179
219
  "POST",
180
220
  "/v1/checkout/sessions",
181
- params
221
+ body
182
222
  );
183
223
  if (res.data) {
184
224
  if (res.data.checkout_url) {
@@ -208,7 +248,7 @@ var BitPalCheckoutClient = class {
208
248
  `/v1/checkout/sessions${query ? `?${query}` : ""}`
209
249
  );
210
250
  }
211
- /* ─── 비수탁 결제 (deposit-address) ─── */
251
+ /* ─── 안2 비수탁 결제 (deposit-address) ─── */
212
252
  /**
213
253
  * 공개 세션 조회 (`GET /v1/checkout/sessions/:id/public`) — 인증 불요.
214
254
  *
@@ -224,7 +264,7 @@ var BitPalCheckoutClient = class {
224
264
  /**
225
265
  * 주문별 비수탁 입금주소 발급 (`POST /v1/checkout/sessions/:id/deposit-address`).
226
266
  *
227
- * 비수탁 결제 진입점. 구매자가 자산(멀티옵션이면 chain/token)과 환불 주소를 확정하면 서버가
267
+ * 안2 결제 진입점. 구매자가 자산(멀티옵션이면 chain/token)과 환불 주소를 확정하면 서버가
228
268
  * 그 주문 전용 CREATE2 forwarder 주소를 돌려준다. 구매자는 아무 지갑/거래소에서 **정확한 금액**을
229
269
  * 그 주소로 일반 송금하면 된다(서명·연결 불필요). watcher 가 감지 → keeper 가 정산.
230
270
  *
@@ -329,26 +369,40 @@ function parseWebhookEvent(body) {
329
369
  }
330
370
 
331
371
  // src/amount.ts
332
- var USDC_DECIMALS = 6n;
333
- var USDC_SCALE = 10n ** USDC_DECIMALS;
334
- function toAtomicUSDC(decimal) {
335
- if (typeof decimal !== "string" || !/^\d+(\.\d{1,6})?$/.test(decimal)) {
336
- throw new Error(`toAtomicUSDC: invalid decimal '${decimal}' (max 6 fractional digits, no negatives)`);
372
+ function toAtomic(decimal, decimals) {
373
+ if (!Number.isInteger(decimals) || decimals < 0 || decimals > 36) {
374
+ throw new Error(`toAtomic: invalid decimals '${decimals}'`);
375
+ }
376
+ const fracPattern = decimals > 0 ? `(\\.\\d{1,${decimals}})?` : "";
377
+ if (typeof decimal !== "string" || !new RegExp(`^\\d+${fracPattern}$`).test(decimal)) {
378
+ throw new Error(`toAtomic: invalid decimal '${decimal}' (max ${decimals} fractional digits, no negatives)`);
337
379
  }
380
+ const scale = 10n ** BigInt(decimals);
338
381
  const [whole = "0", frac = ""] = decimal.split(".");
339
- const fracPadded = frac.padEnd(Number(USDC_DECIMALS), "0");
340
- return (BigInt(whole) * USDC_SCALE + BigInt(fracPadded || "0")).toString();
382
+ const fracPadded = frac.padEnd(decimals, "0");
383
+ return (BigInt(whole) * scale + BigInt(fracPadded || "0")).toString();
341
384
  }
342
- function fromAtomicUSDC(atomic) {
385
+ function fromAtomic(atomic, decimals) {
386
+ if (!Number.isInteger(decimals) || decimals < 0 || decimals > 36) {
387
+ throw new Error(`fromAtomic: invalid decimals '${decimals}'`);
388
+ }
343
389
  if (typeof atomic !== "string" || !/^\d+$/.test(atomic)) {
344
- throw new Error(`fromAtomicUSDC: invalid atomic '${atomic}' (must be non-negative integer string)`);
390
+ throw new Error(`fromAtomic: invalid atomic '${atomic}' (must be non-negative integer string)`);
345
391
  }
392
+ const scale = 10n ** BigInt(decimals);
346
393
  const big = BigInt(atomic);
347
- const whole = big / USDC_SCALE;
348
- const frac = big % USDC_SCALE;
349
- const fracStr = frac.toString().padStart(Number(USDC_DECIMALS), "0").replace(/0+$/, "");
394
+ const whole = big / scale;
395
+ const frac = big % scale;
396
+ if (decimals === 0) return `${whole}`;
397
+ const fracStr = frac.toString().padStart(decimals, "0").replace(/0+$/, "");
350
398
  return fracStr.length > 0 ? `${whole}.${fracStr.padEnd(2, "0")}` : `${whole}.00`;
351
399
  }
400
+ function toAtomicUSDC(decimal) {
401
+ return toAtomic(decimal, 6);
402
+ }
403
+ function fromAtomicUSDC(atomic) {
404
+ return fromAtomic(atomic, 6);
405
+ }
352
406
 
353
407
  // src/index.ts
354
408
  var BitPal = class {
@@ -364,11 +418,14 @@ var BitPal = class {
364
418
  BitPalCheckoutClient,
365
419
  BitPalError,
366
420
  CHECKOUT_WEBHOOK_EVENTS,
421
+ PaymentLinksResource,
367
422
  PricesResource,
368
423
  ProductsResource,
369
424
  WEBHOOK_HEADERS,
425
+ fromAtomic,
370
426
  fromAtomicUSDC,
371
427
  parseWebhookEvent,
428
+ toAtomic,
372
429
  toAtomicUSDC,
373
430
  verifyWebhookSignature
374
431
  });
package/dist/index.d.cts CHANGED
@@ -25,23 +25,36 @@ interface BitPalConfig {
25
25
  /** 요청 타임아웃 (ms, 기본값: 30000) */
26
26
  timeout?: number;
27
27
  }
28
+ /** 응답/정규화된 line item — amount 는 항상 atomic μUSD 정수. */
28
29
  interface LineItem {
29
30
  name: string;
30
- /**
31
- * Atomic μUSDC 정수 문자열 (USDC/USDT 6 decimals).
32
- * $1 = "1000000", $29 = "29000000".
33
- * decimal 표기는 거부된다 — `toAtomicUSDC('29.00')` 헬퍼 사용 권장.
34
- */
31
+ /** Atomic μUSD 정수 문자열($1="1000000", $29="29000000"). */
35
32
  amount: string;
36
33
  currency: string;
37
34
  quantity?: number;
38
35
  }
36
+ /**
37
+ * 세션 생성 입력용 line item. 금액은 둘 중 **하나**:
38
+ * - `amount`(권장): 사람 표기 USD 문자열(예 "29", "0.5", "29.00"). decimal 신경 쓸 필요 없음.
39
+ * ※ 금액은 **USD 가격**이다(체인/토큰 decimal 무관). 토큰(USDC 6dp / BNB USDT 18dp)별 스케일은 발급 시 서버가 처리.
40
+ * - `amount_atomic`: 이미 raw μUSD 정수 문자열($1="1000000")인 경우(고급/기존 코드).
41
+ * 둘 다 지정하거나 둘 다 생략하면 SDK 가 에러를 throw 한다.
42
+ */
43
+ interface LineItemInput {
44
+ name: string;
45
+ currency: string;
46
+ quantity?: number;
47
+ /** 사람 표기 USD 금액(예 "29", "0.5") — 권장. amount_atomic 과 상호배타. */
48
+ amount?: string;
49
+ /** raw μUSD 정수($1="1000000") — 고급/기존. amount 와 상호배타. */
50
+ amount_atomic?: string;
51
+ }
39
52
  interface PriceLineItem {
40
53
  /** price_... — bitpal.checkout.prices.create()로 만든 가격 */
41
54
  price_id: string;
42
55
  quantity?: number;
43
56
  }
44
- type CheckoutLineItemInput = LineItem | PriceLineItem;
57
+ type CheckoutLineItemInput = LineItemInput | PriceLineItem;
45
58
  interface CreateSessionParams {
46
59
  line_items: CheckoutLineItemInput[];
47
60
  /** 고객 지갑 주소 (선택) */
@@ -83,7 +96,7 @@ interface CheckoutSession {
83
96
  settled_at: string | null;
84
97
  tx_hash: string | null;
85
98
  created_at: string;
86
- /** 'hosted' — 결제 경로. hosted deposit-address 단일 경로. */
99
+ /** 'hosted' — 결제 경로. 안2 는 hosted deposit-address 단일 경로. */
87
100
  payment_source?: string;
88
101
  /** 호스티드 결제 페이지 URL (token 쿼리 포함). backend 응답 그대로 사용 — buyer를 이 URL로 redirect. */
89
102
  checkout_url?: string;
@@ -93,15 +106,19 @@ interface CheckoutSession {
93
106
  url: string;
94
107
  }
95
108
  /**
96
- * 결제 옵션(chain×token). `/public` 이 서버 권위로 내려주며, buyer 가 하나를 골라
109
+ * 안2 결제 옵션(chain×token). `/public` 이 서버 권위로 내려주며, buyer 가 하나를 골라
97
110
  * `issueDepositAddress({ chain, token })` 로 입금주소를 발급받는다. 단일-자산 세션은 1개.
98
111
  */
99
112
  interface PaymentOption {
100
- /** CAIP-2 (예: eip155:8453) */
113
+ /** CAIP-2 (예: eip155:8453, tron:0x2b6653dc, solana:5eykt4…). 체인 식별의 canonical. */
101
114
  caip2: string;
102
- chain_id: number;
115
+ /** EVM numeric chainId. 비-EVM(Tron/Solana)은 null — 식별은 caip2 사용. */
116
+ chain_id: number | null;
103
117
  token_symbol: string;
118
+ /** 토큰 컨트랙트/mint 주소(EVM 0x / Tron base58 / Solana base58 mint). */
104
119
  token_address: string;
120
+ /** 토큰 decimals(USDC/USDT=6, BSC-USD=18). atomic↔decimal 변환에 필수 — 6dp 가정 금지. */
121
+ decimals: number;
105
122
  }
106
123
  /**
107
124
  * `getPublicSession()` (`GET /v1/checkout/sessions/:id/public`) 응답 — 인증 불요(공개).
@@ -124,6 +141,8 @@ interface PublicSession {
124
141
  payment_options: PaymentOption[];
125
142
  chain_id: number | null;
126
143
  token_address: string | null;
144
+ /** 선택된 pay 토큰 decimals(발급 후). amount_total/amount_received atomic 해석에 사용 — 6dp 가정 금지. */
145
+ token_decimals?: number | null;
127
146
  tx_hash: string | null;
128
147
  release_tx_hash?: string | null;
129
148
  expires_at: string | null;
@@ -145,7 +164,11 @@ interface PublicSession {
145
164
  interface IssueDepositAddressParams {
146
165
  /** 결제 페이지 접근 증명(HMAC). createSession 응답의 session_token. */
147
166
  session_token: string;
148
- /** 환불 주소(0x EVM). 필수. */
167
+ /**
168
+ * 환불 주소. 필수. 선택한 체인의 VM 형식이어야 한다:
169
+ * EVM=0x…, Tron=base58(T…), Solana=base58. 결제와 같은 네트워크의 본인 주소.
170
+ * 금액부족/잘못된토큰/만료 시 이 주소로 환불되며, 입금주소에 커밋되어 발급 후 변경 불가.
171
+ */
149
172
  refundAddress: string;
150
173
  /** 선택 자산의 chain(CAIP-2 또는 short-name). 멀티옵션 세션 필수. */
151
174
  chain?: string;
@@ -158,7 +181,7 @@ interface IssueDepositAddressParams {
158
181
  interface DepositAddress {
159
182
  sessionId: string;
160
183
  chain: string;
161
- /** 주문별 CREATE2 forwarder 입금주소. */
184
+ /** 주문별 결정적 입금주소(EVM/Tron=CREATE2 forwarder, Solana=order PDA 의 deposit ATA). */
162
185
  depositAddress: string;
163
186
  expectedToken: string;
164
187
  /** Atomic 정수 문자열. */
@@ -248,9 +271,17 @@ interface UpdateProductParams {
248
271
  metadata?: Record<string, unknown>;
249
272
  status?: 'active' | 'inactive';
250
273
  }
274
+ /**
275
+ * 가격 생성 입력. 금액은 둘 중 **하나** (line item 과 동일 모델):
276
+ * - `amount`(권장): 사람 표기 USD 문자열(예 "29", "0.5"). decimal 신경 쓸 필요 없음.
277
+ * - `amount_atomic`: raw μUSD 정수($1="1000000") — 고급/기존.
278
+ * 둘 다 지정하거나 둘 다 생략하면 서버가 400 을 반환한다.
279
+ */
251
280
  interface CreatePriceParams {
252
- /** 원자 단위 정수 문자열 ($1 = "1000000"). `toAtomicUSDC('1.00')` 헬퍼 사용 권장 */
253
- amount_atomic: string;
281
+ /** 사람 표기 USD 금액(예 "29", "0.5") — 권장. amount_atomic 과 상호배타. */
282
+ amount?: string;
283
+ /** raw μUSD 정수($1="1000000") — 고급/기존. amount 와 상호배타. */
284
+ amount_atomic?: string;
254
285
  currency?: string;
255
286
  token_symbol?: string;
256
287
  billing_type?: 'one_time';
@@ -274,6 +305,80 @@ interface ListPricesParams {
274
305
  limit?: number;
275
306
  offset?: number;
276
307
  }
308
+ interface CheckoutPaymentLink {
309
+ /** plink_... */
310
+ id: string;
311
+ /** 고엔트로피 공개 토큰 — 호스티드 URL `{checkoutBase}/plink/{share_token}` 에 사용 */
312
+ share_token: string;
313
+ /** price_... — 이 링크가 파는 가격(생성 후 고정) */
314
+ price_id: string;
315
+ title: string | null;
316
+ description: string | null;
317
+ collect_email: boolean;
318
+ email_required: boolean;
319
+ /** CAIP-2 목록 또는 null(legacy) */
320
+ allowed_pay_chains: string[] | null;
321
+ /** chain×token cell 목록 또는 null */
322
+ allowed_assets: Array<{
323
+ caip2: string;
324
+ token: string;
325
+ }> | null;
326
+ success_url: string | null;
327
+ cancel_url: string | null;
328
+ /** 'active' | 'inactive' */
329
+ status: string;
330
+ max_uses: number | null;
331
+ paid_use_count: number;
332
+ expires_at: string | null;
333
+ mode: string;
334
+ created_at: string;
335
+ updated_at: string;
336
+ }
337
+ interface CreatePaymentLinkParams {
338
+ /** price_... — bitpal.checkout.prices.create() 로 만든 가격. 필수. */
339
+ price_id: string;
340
+ title?: string;
341
+ description?: string;
342
+ /** buyer 이메일 수집(기본 true) */
343
+ collect_email?: boolean;
344
+ /** buyer 이메일 필수(기본 true). true 면 collect_email 도 true 여야 함. */
345
+ email_required?: boolean;
346
+ /** 허용 결제 체인(CAIP-2 또는 short-name). allowed_assets 가 있으면 그쪽 우선. */
347
+ allowed_pay_chains?: string[];
348
+ /** chain×token cell 허용 목록 — allowed_pay_chains 보다 우선. */
349
+ allowed_assets?: Array<{
350
+ chain: string;
351
+ token: string;
352
+ }>;
353
+ success_url?: string;
354
+ cancel_url?: string;
355
+ max_uses?: number;
356
+ /** ISO-8601 datetime */
357
+ expires_at?: string;
358
+ metadata?: Record<string, unknown>;
359
+ }
360
+ interface UpdatePaymentLinkParams {
361
+ title?: string | null;
362
+ description?: string | null;
363
+ collect_email?: boolean;
364
+ email_required?: boolean;
365
+ allowed_pay_chains?: string[] | null;
366
+ allowed_assets?: Array<{
367
+ chain: string;
368
+ token: string;
369
+ }> | null;
370
+ success_url?: string | null;
371
+ cancel_url?: string | null;
372
+ status?: 'active' | 'inactive';
373
+ max_uses?: number | null;
374
+ expires_at?: string | null;
375
+ metadata?: Record<string, unknown>;
376
+ }
377
+ interface ListPaymentLinksParams {
378
+ status?: 'active' | 'inactive';
379
+ limit?: number;
380
+ offset?: number;
381
+ }
277
382
 
278
383
  /**
279
384
  * catalog.ts — Product / immutable Price 관리 리소스 (PROD-LINK-3a-SDK)
@@ -325,6 +430,33 @@ declare class PricesResource {
325
430
  */
326
431
  update(priceId: string, params: UpdatePriceParams): Promise<ApiResponse<CheckoutPrice>>;
327
432
  }
433
+ /**
434
+ * Payment Link 리소스 — 대시보드 없이 코드로 결제 링크 생성/관리 (PROD-LINK-4).
435
+ *
436
+ * 흐름: product 생성 → price 생성 → payment link 생성. link↔price binding 은 생성 후 고정.
437
+ *
438
+ * ```ts
439
+ * const { data: product } = await bitpal.checkout.products.create({ name: 'Pro Plan' });
440
+ * const { data: price } = await bitpal.checkout.prices.create(product.id, { amount: '29' });
441
+ * const { data: link } = await bitpal.checkout.paymentLinks.create({
442
+ * price_id: price.id,
443
+ * allowed_pay_chains: ['eip155:8453', 'solana:5eykt4Us…'],
444
+ * });
445
+ * // 호스티드 결제 페이지 URL: `{checkoutBase}/plink/${link.share_token}`
446
+ * ```
447
+ */
448
+ declare class PaymentLinksResource {
449
+ private readonly request;
450
+ constructor(request: CatalogRequester);
451
+ /** POST /v1/checkout/payment-links */
452
+ create(params: CreatePaymentLinkParams): Promise<ApiResponse<CheckoutPaymentLink>>;
453
+ /** GET /v1/checkout/payment-links */
454
+ list(params?: ListPaymentLinksParams): Promise<ListResponse<CheckoutPaymentLink>>;
455
+ /** GET /v1/checkout/payment-links/:id */
456
+ retrieve(linkId: string): Promise<ApiResponse<CheckoutPaymentLink>>;
457
+ /** PATCH /v1/checkout/payment-links/:id */
458
+ update(linkId: string, params: UpdatePaymentLinkParams): Promise<ApiResponse<CheckoutPaymentLink>>;
459
+ }
328
460
 
329
461
  /**
330
462
  * @bitpal/checkout SDK — 클라이언트
@@ -342,25 +474,29 @@ declare class BitPalCheckoutClient {
342
474
  readonly products: ProductsResource;
343
475
  /** PROD-LINK-3a-SDK: immutable Price 관리 — 가격 변경은 비활성화 + 새 price 생성 */
344
476
  readonly prices: PricesResource;
477
+ /** PROD-LINK-4-SDK: Payment Link 관리 — 대시보드 없이 코드로 결제 링크 생성 (server-side 전용) */
478
+ readonly paymentLinks: PaymentLinksResource;
345
479
  constructor(config: BitPalConfig);
346
480
  private request;
347
481
  /**
348
482
  * 체크아웃 세션 생성.
349
483
  *
350
- * 모든 `line_items[].amount`는 atomic μUSDC 정수 문자열이어야 한다 ($1 = "1000000").
351
- * decimal 표기는 거부된다 — `toAtomicUSDC()` 헬퍼 사용 권장.
484
+ * `line_items[].amount` 는 사람 표기 USD 문자열("29", "0.5") — decimal 계산 불필요.
485
+ * 이미 raw μUSD 정수라면 `amount_atomic`("29000000") 사용(고급). 둘은 상호 배타.
352
486
  *
353
487
  * @example
354
- * import { BitPal, toAtomicUSDC } from '@bitpal/checkout';
488
+ * import { BitPal } from '@bitpal/checkout';
355
489
  * const bp = new BitPal('bp_test_...');
356
490
  * const { data } = await bp.checkout.createSession({
357
- * line_items: [{ name: 'Pro', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
491
+ * // amount: 사람 표기 USD("29", "0.5"). 금액은 USD 가격이라 체인/토큰 decimal 무관.
492
+ * line_items: [{ name: 'Pro', amount: '29', currency: 'USDC' }],
358
493
  * });
359
494
  * console.log(data.url); // → buyer를 redirect할 결제 페이지
360
495
  *
361
496
  * // 멀티체인 허용 — 구매자가 Base/Optimism 중 선택(하나뿐이면 자동 선택):
497
+ * // 어떤 체인·토큰이든 amount 그대로 — 서버가 발급 시 토큰 decimals 로 재스케일.
362
498
  * await bp.checkout.createSession({
363
- * line_items: [{ name: 'Pro', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
499
+ * line_items: [{ name: 'Pro', amount: '29', currency: 'USDC' }],
364
500
  * allowed_pay_chains: ['eip155:84532', 'eip155:11155420'],
365
501
  * });
366
502
  * // 단일 체인 고정은 pay_chain 사용(둘은 상호 배타).
@@ -384,7 +520,7 @@ declare class BitPalCheckoutClient {
384
520
  /**
385
521
  * 주문별 비수탁 입금주소 발급 (`POST /v1/checkout/sessions/:id/deposit-address`).
386
522
  *
387
- * 비수탁 결제 진입점. 구매자가 자산(멀티옵션이면 chain/token)과 환불 주소를 확정하면 서버가
523
+ * 안2 결제 진입점. 구매자가 자산(멀티옵션이면 chain/token)과 환불 주소를 확정하면 서버가
388
524
  * 그 주문 전용 CREATE2 forwarder 주소를 돌려준다. 구매자는 아무 지갑/거래소에서 **정확한 금액**을
389
525
  * 그 주소로 일반 송금하면 된다(서명·연결 불필요). watcher 가 감지 → keeper 가 정산.
390
526
  *
@@ -503,35 +639,41 @@ declare function verifyWebhookSignature(payload: string, signature: string, secr
503
639
  declare function parseWebhookEvent(body: string): WebhookPayload;
504
640
 
505
641
  /**
506
- * amount.ts — atomic μUSDC 변환 헬퍼
642
+ * amount.ts — atomic ↔ decimal 변환 헬퍼 (임의 decimals + USDC 하위호환)
507
643
  *
508
- * BitPal API는 모든 amount를 atomic 정수 문자열로 받는다 (USDC/USDT 6 decimals).
509
- * $1 → "1000000"
510
- * $10 → "10000000"
511
- * $0.5 → "500000"
644
+ * BitPal API는 모든 amount를 atomic 정수 문자열로 받는다. decimals 는 토큰마다 다르다:
645
+ * USDC/USDT(Base/Arb/Tron/Solana) = 6, BSC-USD(BNB USDT) = 18. → payment_options[].decimals /
646
+ * PublicSession.token_decimals 로 서버가 내려준다. 6dp 를 하드코딩하면 non-6dp 토큰에서 금액이 틀린다.
512
647
  *
513
648
  * 정밀도 손실 방지를 위해 BigInt 연산만 사용한다 (Number 변환 금지 — CLAUDE.md 정책).
649
+ * $1(6dp) → "1000000" $1(18dp) → "1000000000000000000"
514
650
  */
515
651
  /**
516
- * decimal 문자열 → atomic μUSDC 문자열
517
- *
518
- * @example
519
- * toAtomicUSDC('29.00') // → '29000000'
520
- * toAtomicUSDC('0.5') // → '500000'
521
- * toAtomicUSDC('1000') // → '1000000000'
652
+ * decimal 문자열 → atomic 문자열 (임의 decimals).
522
653
  *
523
- * @throws {Error} 음수, 6자리 초과 소수, 형식 오류
654
+ * @param decimal 소수 문자열(음수 불가, 소수 자리 ≤ decimals)
655
+ * @param decimals 토큰 decimals (예: 6, 18). payment_options[].decimals 사용.
656
+ * @throws {Error} 음수, decimals 초과 소수 자리, 형식 오류
657
+ * @example toAtomic('29.00', 6) // '29000000' toAtomic('1.5', 18) // '1500000000000000000'
524
658
  */
525
- declare function toAtomicUSDC(decimal: string): string;
659
+ declare function toAtomic(decimal: string, decimals: number): string;
526
660
  /**
527
- * atomic μUSDC 문자열 → 사람이 읽기 좋은 decimal 문자열
528
- *
529
- * @example
530
- * fromAtomicUSDC('29000000') // → '29.00'
531
- * fromAtomicUSDC('500000') // → '0.50'
532
- * fromAtomicUSDC('1500000') // → '1.50'
661
+ * atomic 문자열 → 사람이 읽기 좋은 decimal 문자열 (임의 decimals).
662
+ * 최소 2자리 소수를 유지하되(예: '29.00'), decimals 만큼만 노출.
533
663
  *
534
664
  * @throws {Error} 정수 문자열이 아니면
665
+ * @example fromAtomic('29000000', 6) // '29.00' fromAtomic('1500000000000000000', 18) // '1.50'
666
+ */
667
+ declare function fromAtomic(atomic: string, decimals: number): string;
668
+ /**
669
+ * decimal → atomic μUSDC (6dp). 하위호환 별칭 — 새 코드는 `toAtomic(decimal, decimals)` 권장
670
+ * (BNB USDT=18dp 등 non-6dp 토큰은 이 헬퍼로 처리 불가).
671
+ * @example toAtomicUSDC('29.00') // '29000000'
672
+ */
673
+ declare function toAtomicUSDC(decimal: string): string;
674
+ /**
675
+ * atomic μUSDC(6dp) → decimal. 하위호환 별칭 — 새 코드는 `fromAtomic(atomic, decimals)` 권장.
676
+ * @example fromAtomicUSDC('29000000') // '29.00'
535
677
  */
536
678
  declare function fromAtomicUSDC(atomic: string): string;
537
679
 
@@ -547,8 +689,8 @@ declare function fromAtomicUSDC(atomic: string): string;
547
689
  * const bitpal = new BitPal({ apiKey: 'bp_test_...' });
548
690
  *
549
691
  * const { data: session } = await bitpal.checkout.createSession({
550
- * // amount 는 원자 단위 μUSDC 문자열(6 decimals). $29.00 → '29000000'. toAtomicUSDC 사용 권장.
551
- * line_items: [{ name: 'Pro Plan', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
692
+ * // amount: 사람 표기 USD("29","0.5"). decimal 계산 불필요 — 체인/토큰 decimal 무관.
693
+ * line_items: [{ name: 'Pro Plan', amount: '29', currency: 'USDC' }],
552
694
  * });
553
695
  *
554
696
  * console.log(session.url); // 호스티드 결제 페이지 URL (checkout_url 별칭)
@@ -563,4 +705,4 @@ declare class BitPal {
563
705
  constructor(config: BitPalConfig | string);
564
706
  }
565
707
 
566
- export { type ApiResponse, BitPal, BitPalCheckoutClient, type BitPalConfig, BitPalError, CHECKOUT_WEBHOOK_EVENTS, type CheckoutLineItemInput, type CheckoutPrice, type CheckoutProduct, type CheckoutSession, type CheckoutWebhookEvent, type CreatePriceParams, type CreateProductParams, type CreateSessionParams, type DepositAddress, type FeePreview, type IdempotencyOptions, type IssueDepositAddressParams, type LineItem, type ListPricesParams, type ListProductsParams, type ListResponse, type PaymentOption, type PriceLineItem, PricesResource, ProductsResource, type PublicSession, type SessionStatus, type UpdatePriceParams, type UpdateProductParams, WEBHOOK_HEADERS, type WebhookPayload, fromAtomicUSDC, parseWebhookEvent, toAtomicUSDC, verifyWebhookSignature };
708
+ export { type ApiResponse, BitPal, BitPalCheckoutClient, type BitPalConfig, BitPalError, CHECKOUT_WEBHOOK_EVENTS, type CheckoutLineItemInput, type CheckoutPaymentLink, type CheckoutPrice, type CheckoutProduct, type CheckoutSession, type CheckoutWebhookEvent, type CreatePaymentLinkParams, type CreatePriceParams, type CreateProductParams, type CreateSessionParams, type DepositAddress, type FeePreview, type IdempotencyOptions, type IssueDepositAddressParams, type LineItem, type ListPaymentLinksParams, type ListPricesParams, type ListProductsParams, type ListResponse, PaymentLinksResource, type PaymentOption, type PriceLineItem, PricesResource, ProductsResource, type PublicSession, type SessionStatus, type UpdatePaymentLinkParams, type UpdatePriceParams, type UpdateProductParams, WEBHOOK_HEADERS, type WebhookPayload, fromAtomic, fromAtomicUSDC, parseWebhookEvent, toAtomic, toAtomicUSDC, verifyWebhookSignature };
package/dist/index.d.ts CHANGED
@@ -25,23 +25,36 @@ interface BitPalConfig {
25
25
  /** 요청 타임아웃 (ms, 기본값: 30000) */
26
26
  timeout?: number;
27
27
  }
28
+ /** 응답/정규화된 line item — amount 는 항상 atomic μUSD 정수. */
28
29
  interface LineItem {
29
30
  name: string;
30
- /**
31
- * Atomic μUSDC 정수 문자열 (USDC/USDT 6 decimals).
32
- * $1 = "1000000", $29 = "29000000".
33
- * decimal 표기는 거부된다 — `toAtomicUSDC('29.00')` 헬퍼 사용 권장.
34
- */
31
+ /** Atomic μUSD 정수 문자열($1="1000000", $29="29000000"). */
35
32
  amount: string;
36
33
  currency: string;
37
34
  quantity?: number;
38
35
  }
36
+ /**
37
+ * 세션 생성 입력용 line item. 금액은 둘 중 **하나**:
38
+ * - `amount`(권장): 사람 표기 USD 문자열(예 "29", "0.5", "29.00"). decimal 신경 쓸 필요 없음.
39
+ * ※ 금액은 **USD 가격**이다(체인/토큰 decimal 무관). 토큰(USDC 6dp / BNB USDT 18dp)별 스케일은 발급 시 서버가 처리.
40
+ * - `amount_atomic`: 이미 raw μUSD 정수 문자열($1="1000000")인 경우(고급/기존 코드).
41
+ * 둘 다 지정하거나 둘 다 생략하면 SDK 가 에러를 throw 한다.
42
+ */
43
+ interface LineItemInput {
44
+ name: string;
45
+ currency: string;
46
+ quantity?: number;
47
+ /** 사람 표기 USD 금액(예 "29", "0.5") — 권장. amount_atomic 과 상호배타. */
48
+ amount?: string;
49
+ /** raw μUSD 정수($1="1000000") — 고급/기존. amount 와 상호배타. */
50
+ amount_atomic?: string;
51
+ }
39
52
  interface PriceLineItem {
40
53
  /** price_... — bitpal.checkout.prices.create()로 만든 가격 */
41
54
  price_id: string;
42
55
  quantity?: number;
43
56
  }
44
- type CheckoutLineItemInput = LineItem | PriceLineItem;
57
+ type CheckoutLineItemInput = LineItemInput | PriceLineItem;
45
58
  interface CreateSessionParams {
46
59
  line_items: CheckoutLineItemInput[];
47
60
  /** 고객 지갑 주소 (선택) */
@@ -83,7 +96,7 @@ interface CheckoutSession {
83
96
  settled_at: string | null;
84
97
  tx_hash: string | null;
85
98
  created_at: string;
86
- /** 'hosted' — 결제 경로. hosted deposit-address 단일 경로. */
99
+ /** 'hosted' — 결제 경로. 안2 는 hosted deposit-address 단일 경로. */
87
100
  payment_source?: string;
88
101
  /** 호스티드 결제 페이지 URL (token 쿼리 포함). backend 응답 그대로 사용 — buyer를 이 URL로 redirect. */
89
102
  checkout_url?: string;
@@ -93,15 +106,19 @@ interface CheckoutSession {
93
106
  url: string;
94
107
  }
95
108
  /**
96
- * 결제 옵션(chain×token). `/public` 이 서버 권위로 내려주며, buyer 가 하나를 골라
109
+ * 안2 결제 옵션(chain×token). `/public` 이 서버 권위로 내려주며, buyer 가 하나를 골라
97
110
  * `issueDepositAddress({ chain, token })` 로 입금주소를 발급받는다. 단일-자산 세션은 1개.
98
111
  */
99
112
  interface PaymentOption {
100
- /** CAIP-2 (예: eip155:8453) */
113
+ /** CAIP-2 (예: eip155:8453, tron:0x2b6653dc, solana:5eykt4…). 체인 식별의 canonical. */
101
114
  caip2: string;
102
- chain_id: number;
115
+ /** EVM numeric chainId. 비-EVM(Tron/Solana)은 null — 식별은 caip2 사용. */
116
+ chain_id: number | null;
103
117
  token_symbol: string;
118
+ /** 토큰 컨트랙트/mint 주소(EVM 0x / Tron base58 / Solana base58 mint). */
104
119
  token_address: string;
120
+ /** 토큰 decimals(USDC/USDT=6, BSC-USD=18). atomic↔decimal 변환에 필수 — 6dp 가정 금지. */
121
+ decimals: number;
105
122
  }
106
123
  /**
107
124
  * `getPublicSession()` (`GET /v1/checkout/sessions/:id/public`) 응답 — 인증 불요(공개).
@@ -124,6 +141,8 @@ interface PublicSession {
124
141
  payment_options: PaymentOption[];
125
142
  chain_id: number | null;
126
143
  token_address: string | null;
144
+ /** 선택된 pay 토큰 decimals(발급 후). amount_total/amount_received atomic 해석에 사용 — 6dp 가정 금지. */
145
+ token_decimals?: number | null;
127
146
  tx_hash: string | null;
128
147
  release_tx_hash?: string | null;
129
148
  expires_at: string | null;
@@ -145,7 +164,11 @@ interface PublicSession {
145
164
  interface IssueDepositAddressParams {
146
165
  /** 결제 페이지 접근 증명(HMAC). createSession 응답의 session_token. */
147
166
  session_token: string;
148
- /** 환불 주소(0x EVM). 필수. */
167
+ /**
168
+ * 환불 주소. 필수. 선택한 체인의 VM 형식이어야 한다:
169
+ * EVM=0x…, Tron=base58(T…), Solana=base58. 결제와 같은 네트워크의 본인 주소.
170
+ * 금액부족/잘못된토큰/만료 시 이 주소로 환불되며, 입금주소에 커밋되어 발급 후 변경 불가.
171
+ */
149
172
  refundAddress: string;
150
173
  /** 선택 자산의 chain(CAIP-2 또는 short-name). 멀티옵션 세션 필수. */
151
174
  chain?: string;
@@ -158,7 +181,7 @@ interface IssueDepositAddressParams {
158
181
  interface DepositAddress {
159
182
  sessionId: string;
160
183
  chain: string;
161
- /** 주문별 CREATE2 forwarder 입금주소. */
184
+ /** 주문별 결정적 입금주소(EVM/Tron=CREATE2 forwarder, Solana=order PDA 의 deposit ATA). */
162
185
  depositAddress: string;
163
186
  expectedToken: string;
164
187
  /** Atomic 정수 문자열. */
@@ -248,9 +271,17 @@ interface UpdateProductParams {
248
271
  metadata?: Record<string, unknown>;
249
272
  status?: 'active' | 'inactive';
250
273
  }
274
+ /**
275
+ * 가격 생성 입력. 금액은 둘 중 **하나** (line item 과 동일 모델):
276
+ * - `amount`(권장): 사람 표기 USD 문자열(예 "29", "0.5"). decimal 신경 쓸 필요 없음.
277
+ * - `amount_atomic`: raw μUSD 정수($1="1000000") — 고급/기존.
278
+ * 둘 다 지정하거나 둘 다 생략하면 서버가 400 을 반환한다.
279
+ */
251
280
  interface CreatePriceParams {
252
- /** 원자 단위 정수 문자열 ($1 = "1000000"). `toAtomicUSDC('1.00')` 헬퍼 사용 권장 */
253
- amount_atomic: string;
281
+ /** 사람 표기 USD 금액(예 "29", "0.5") — 권장. amount_atomic 과 상호배타. */
282
+ amount?: string;
283
+ /** raw μUSD 정수($1="1000000") — 고급/기존. amount 와 상호배타. */
284
+ amount_atomic?: string;
254
285
  currency?: string;
255
286
  token_symbol?: string;
256
287
  billing_type?: 'one_time';
@@ -274,6 +305,80 @@ interface ListPricesParams {
274
305
  limit?: number;
275
306
  offset?: number;
276
307
  }
308
+ interface CheckoutPaymentLink {
309
+ /** plink_... */
310
+ id: string;
311
+ /** 고엔트로피 공개 토큰 — 호스티드 URL `{checkoutBase}/plink/{share_token}` 에 사용 */
312
+ share_token: string;
313
+ /** price_... — 이 링크가 파는 가격(생성 후 고정) */
314
+ price_id: string;
315
+ title: string | null;
316
+ description: string | null;
317
+ collect_email: boolean;
318
+ email_required: boolean;
319
+ /** CAIP-2 목록 또는 null(legacy) */
320
+ allowed_pay_chains: string[] | null;
321
+ /** chain×token cell 목록 또는 null */
322
+ allowed_assets: Array<{
323
+ caip2: string;
324
+ token: string;
325
+ }> | null;
326
+ success_url: string | null;
327
+ cancel_url: string | null;
328
+ /** 'active' | 'inactive' */
329
+ status: string;
330
+ max_uses: number | null;
331
+ paid_use_count: number;
332
+ expires_at: string | null;
333
+ mode: string;
334
+ created_at: string;
335
+ updated_at: string;
336
+ }
337
+ interface CreatePaymentLinkParams {
338
+ /** price_... — bitpal.checkout.prices.create() 로 만든 가격. 필수. */
339
+ price_id: string;
340
+ title?: string;
341
+ description?: string;
342
+ /** buyer 이메일 수집(기본 true) */
343
+ collect_email?: boolean;
344
+ /** buyer 이메일 필수(기본 true). true 면 collect_email 도 true 여야 함. */
345
+ email_required?: boolean;
346
+ /** 허용 결제 체인(CAIP-2 또는 short-name). allowed_assets 가 있으면 그쪽 우선. */
347
+ allowed_pay_chains?: string[];
348
+ /** chain×token cell 허용 목록 — allowed_pay_chains 보다 우선. */
349
+ allowed_assets?: Array<{
350
+ chain: string;
351
+ token: string;
352
+ }>;
353
+ success_url?: string;
354
+ cancel_url?: string;
355
+ max_uses?: number;
356
+ /** ISO-8601 datetime */
357
+ expires_at?: string;
358
+ metadata?: Record<string, unknown>;
359
+ }
360
+ interface UpdatePaymentLinkParams {
361
+ title?: string | null;
362
+ description?: string | null;
363
+ collect_email?: boolean;
364
+ email_required?: boolean;
365
+ allowed_pay_chains?: string[] | null;
366
+ allowed_assets?: Array<{
367
+ chain: string;
368
+ token: string;
369
+ }> | null;
370
+ success_url?: string | null;
371
+ cancel_url?: string | null;
372
+ status?: 'active' | 'inactive';
373
+ max_uses?: number | null;
374
+ expires_at?: string | null;
375
+ metadata?: Record<string, unknown>;
376
+ }
377
+ interface ListPaymentLinksParams {
378
+ status?: 'active' | 'inactive';
379
+ limit?: number;
380
+ offset?: number;
381
+ }
277
382
 
278
383
  /**
279
384
  * catalog.ts — Product / immutable Price 관리 리소스 (PROD-LINK-3a-SDK)
@@ -325,6 +430,33 @@ declare class PricesResource {
325
430
  */
326
431
  update(priceId: string, params: UpdatePriceParams): Promise<ApiResponse<CheckoutPrice>>;
327
432
  }
433
+ /**
434
+ * Payment Link 리소스 — 대시보드 없이 코드로 결제 링크 생성/관리 (PROD-LINK-4).
435
+ *
436
+ * 흐름: product 생성 → price 생성 → payment link 생성. link↔price binding 은 생성 후 고정.
437
+ *
438
+ * ```ts
439
+ * const { data: product } = await bitpal.checkout.products.create({ name: 'Pro Plan' });
440
+ * const { data: price } = await bitpal.checkout.prices.create(product.id, { amount: '29' });
441
+ * const { data: link } = await bitpal.checkout.paymentLinks.create({
442
+ * price_id: price.id,
443
+ * allowed_pay_chains: ['eip155:8453', 'solana:5eykt4Us…'],
444
+ * });
445
+ * // 호스티드 결제 페이지 URL: `{checkoutBase}/plink/${link.share_token}`
446
+ * ```
447
+ */
448
+ declare class PaymentLinksResource {
449
+ private readonly request;
450
+ constructor(request: CatalogRequester);
451
+ /** POST /v1/checkout/payment-links */
452
+ create(params: CreatePaymentLinkParams): Promise<ApiResponse<CheckoutPaymentLink>>;
453
+ /** GET /v1/checkout/payment-links */
454
+ list(params?: ListPaymentLinksParams): Promise<ListResponse<CheckoutPaymentLink>>;
455
+ /** GET /v1/checkout/payment-links/:id */
456
+ retrieve(linkId: string): Promise<ApiResponse<CheckoutPaymentLink>>;
457
+ /** PATCH /v1/checkout/payment-links/:id */
458
+ update(linkId: string, params: UpdatePaymentLinkParams): Promise<ApiResponse<CheckoutPaymentLink>>;
459
+ }
328
460
 
329
461
  /**
330
462
  * @bitpal/checkout SDK — 클라이언트
@@ -342,25 +474,29 @@ declare class BitPalCheckoutClient {
342
474
  readonly products: ProductsResource;
343
475
  /** PROD-LINK-3a-SDK: immutable Price 관리 — 가격 변경은 비활성화 + 새 price 생성 */
344
476
  readonly prices: PricesResource;
477
+ /** PROD-LINK-4-SDK: Payment Link 관리 — 대시보드 없이 코드로 결제 링크 생성 (server-side 전용) */
478
+ readonly paymentLinks: PaymentLinksResource;
345
479
  constructor(config: BitPalConfig);
346
480
  private request;
347
481
  /**
348
482
  * 체크아웃 세션 생성.
349
483
  *
350
- * 모든 `line_items[].amount`는 atomic μUSDC 정수 문자열이어야 한다 ($1 = "1000000").
351
- * decimal 표기는 거부된다 — `toAtomicUSDC()` 헬퍼 사용 권장.
484
+ * `line_items[].amount` 는 사람 표기 USD 문자열("29", "0.5") — decimal 계산 불필요.
485
+ * 이미 raw μUSD 정수라면 `amount_atomic`("29000000") 사용(고급). 둘은 상호 배타.
352
486
  *
353
487
  * @example
354
- * import { BitPal, toAtomicUSDC } from '@bitpal/checkout';
488
+ * import { BitPal } from '@bitpal/checkout';
355
489
  * const bp = new BitPal('bp_test_...');
356
490
  * const { data } = await bp.checkout.createSession({
357
- * line_items: [{ name: 'Pro', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
491
+ * // amount: 사람 표기 USD("29", "0.5"). 금액은 USD 가격이라 체인/토큰 decimal 무관.
492
+ * line_items: [{ name: 'Pro', amount: '29', currency: 'USDC' }],
358
493
  * });
359
494
  * console.log(data.url); // → buyer를 redirect할 결제 페이지
360
495
  *
361
496
  * // 멀티체인 허용 — 구매자가 Base/Optimism 중 선택(하나뿐이면 자동 선택):
497
+ * // 어떤 체인·토큰이든 amount 그대로 — 서버가 발급 시 토큰 decimals 로 재스케일.
362
498
  * await bp.checkout.createSession({
363
- * line_items: [{ name: 'Pro', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
499
+ * line_items: [{ name: 'Pro', amount: '29', currency: 'USDC' }],
364
500
  * allowed_pay_chains: ['eip155:84532', 'eip155:11155420'],
365
501
  * });
366
502
  * // 단일 체인 고정은 pay_chain 사용(둘은 상호 배타).
@@ -384,7 +520,7 @@ declare class BitPalCheckoutClient {
384
520
  /**
385
521
  * 주문별 비수탁 입금주소 발급 (`POST /v1/checkout/sessions/:id/deposit-address`).
386
522
  *
387
- * 비수탁 결제 진입점. 구매자가 자산(멀티옵션이면 chain/token)과 환불 주소를 확정하면 서버가
523
+ * 안2 결제 진입점. 구매자가 자산(멀티옵션이면 chain/token)과 환불 주소를 확정하면 서버가
388
524
  * 그 주문 전용 CREATE2 forwarder 주소를 돌려준다. 구매자는 아무 지갑/거래소에서 **정확한 금액**을
389
525
  * 그 주소로 일반 송금하면 된다(서명·연결 불필요). watcher 가 감지 → keeper 가 정산.
390
526
  *
@@ -503,35 +639,41 @@ declare function verifyWebhookSignature(payload: string, signature: string, secr
503
639
  declare function parseWebhookEvent(body: string): WebhookPayload;
504
640
 
505
641
  /**
506
- * amount.ts — atomic μUSDC 변환 헬퍼
642
+ * amount.ts — atomic ↔ decimal 변환 헬퍼 (임의 decimals + USDC 하위호환)
507
643
  *
508
- * BitPal API는 모든 amount를 atomic 정수 문자열로 받는다 (USDC/USDT 6 decimals).
509
- * $1 → "1000000"
510
- * $10 → "10000000"
511
- * $0.5 → "500000"
644
+ * BitPal API는 모든 amount를 atomic 정수 문자열로 받는다. decimals 는 토큰마다 다르다:
645
+ * USDC/USDT(Base/Arb/Tron/Solana) = 6, BSC-USD(BNB USDT) = 18. → payment_options[].decimals /
646
+ * PublicSession.token_decimals 로 서버가 내려준다. 6dp 를 하드코딩하면 non-6dp 토큰에서 금액이 틀린다.
512
647
  *
513
648
  * 정밀도 손실 방지를 위해 BigInt 연산만 사용한다 (Number 변환 금지 — CLAUDE.md 정책).
649
+ * $1(6dp) → "1000000" $1(18dp) → "1000000000000000000"
514
650
  */
515
651
  /**
516
- * decimal 문자열 → atomic μUSDC 문자열
517
- *
518
- * @example
519
- * toAtomicUSDC('29.00') // → '29000000'
520
- * toAtomicUSDC('0.5') // → '500000'
521
- * toAtomicUSDC('1000') // → '1000000000'
652
+ * decimal 문자열 → atomic 문자열 (임의 decimals).
522
653
  *
523
- * @throws {Error} 음수, 6자리 초과 소수, 형식 오류
654
+ * @param decimal 소수 문자열(음수 불가, 소수 자리 ≤ decimals)
655
+ * @param decimals 토큰 decimals (예: 6, 18). payment_options[].decimals 사용.
656
+ * @throws {Error} 음수, decimals 초과 소수 자리, 형식 오류
657
+ * @example toAtomic('29.00', 6) // '29000000' toAtomic('1.5', 18) // '1500000000000000000'
524
658
  */
525
- declare function toAtomicUSDC(decimal: string): string;
659
+ declare function toAtomic(decimal: string, decimals: number): string;
526
660
  /**
527
- * atomic μUSDC 문자열 → 사람이 읽기 좋은 decimal 문자열
528
- *
529
- * @example
530
- * fromAtomicUSDC('29000000') // → '29.00'
531
- * fromAtomicUSDC('500000') // → '0.50'
532
- * fromAtomicUSDC('1500000') // → '1.50'
661
+ * atomic 문자열 → 사람이 읽기 좋은 decimal 문자열 (임의 decimals).
662
+ * 최소 2자리 소수를 유지하되(예: '29.00'), decimals 만큼만 노출.
533
663
  *
534
664
  * @throws {Error} 정수 문자열이 아니면
665
+ * @example fromAtomic('29000000', 6) // '29.00' fromAtomic('1500000000000000000', 18) // '1.50'
666
+ */
667
+ declare function fromAtomic(atomic: string, decimals: number): string;
668
+ /**
669
+ * decimal → atomic μUSDC (6dp). 하위호환 별칭 — 새 코드는 `toAtomic(decimal, decimals)` 권장
670
+ * (BNB USDT=18dp 등 non-6dp 토큰은 이 헬퍼로 처리 불가).
671
+ * @example toAtomicUSDC('29.00') // '29000000'
672
+ */
673
+ declare function toAtomicUSDC(decimal: string): string;
674
+ /**
675
+ * atomic μUSDC(6dp) → decimal. 하위호환 별칭 — 새 코드는 `fromAtomic(atomic, decimals)` 권장.
676
+ * @example fromAtomicUSDC('29000000') // '29.00'
535
677
  */
536
678
  declare function fromAtomicUSDC(atomic: string): string;
537
679
 
@@ -547,8 +689,8 @@ declare function fromAtomicUSDC(atomic: string): string;
547
689
  * const bitpal = new BitPal({ apiKey: 'bp_test_...' });
548
690
  *
549
691
  * const { data: session } = await bitpal.checkout.createSession({
550
- * // amount 는 원자 단위 μUSDC 문자열(6 decimals). $29.00 → '29000000'. toAtomicUSDC 사용 권장.
551
- * line_items: [{ name: 'Pro Plan', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
692
+ * // amount: 사람 표기 USD("29","0.5"). decimal 계산 불필요 — 체인/토큰 decimal 무관.
693
+ * line_items: [{ name: 'Pro Plan', amount: '29', currency: 'USDC' }],
552
694
  * });
553
695
  *
554
696
  * console.log(session.url); // 호스티드 결제 페이지 URL (checkout_url 별칭)
@@ -563,4 +705,4 @@ declare class BitPal {
563
705
  constructor(config: BitPalConfig | string);
564
706
  }
565
707
 
566
- export { type ApiResponse, BitPal, BitPalCheckoutClient, type BitPalConfig, BitPalError, CHECKOUT_WEBHOOK_EVENTS, type CheckoutLineItemInput, type CheckoutPrice, type CheckoutProduct, type CheckoutSession, type CheckoutWebhookEvent, type CreatePriceParams, type CreateProductParams, type CreateSessionParams, type DepositAddress, type FeePreview, type IdempotencyOptions, type IssueDepositAddressParams, type LineItem, type ListPricesParams, type ListProductsParams, type ListResponse, type PaymentOption, type PriceLineItem, PricesResource, ProductsResource, type PublicSession, type SessionStatus, type UpdatePriceParams, type UpdateProductParams, WEBHOOK_HEADERS, type WebhookPayload, fromAtomicUSDC, parseWebhookEvent, toAtomicUSDC, verifyWebhookSignature };
708
+ export { type ApiResponse, BitPal, BitPalCheckoutClient, type BitPalConfig, BitPalError, CHECKOUT_WEBHOOK_EVENTS, type CheckoutLineItemInput, type CheckoutPaymentLink, type CheckoutPrice, type CheckoutProduct, type CheckoutSession, type CheckoutWebhookEvent, type CreatePaymentLinkParams, type CreatePriceParams, type CreateProductParams, type CreateSessionParams, type DepositAddress, type FeePreview, type IdempotencyOptions, type IssueDepositAddressParams, type LineItem, type ListPaymentLinksParams, type ListPricesParams, type ListProductsParams, type ListResponse, PaymentLinksResource, type PaymentOption, type PriceLineItem, PricesResource, ProductsResource, type PublicSession, type SessionStatus, type UpdatePaymentLinkParams, type UpdatePriceParams, type UpdateProductParams, WEBHOOK_HEADERS, type WebhookPayload, fromAtomic, fromAtomicUSDC, parseWebhookEvent, toAtomic, toAtomicUSDC, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -55,8 +55,39 @@ var PricesResource = class {
55
55
  return this.request("PATCH", `/v1/checkout/prices/${encodeURIComponent(priceId)}`, params);
56
56
  }
57
57
  };
58
+ var PaymentLinksResource = class {
59
+ constructor(request) {
60
+ this.request = request;
61
+ }
62
+ request;
63
+ /** POST /v1/checkout/payment-links */
64
+ create(params) {
65
+ return this.request("POST", "/v1/checkout/payment-links", params);
66
+ }
67
+ /** GET /v1/checkout/payment-links */
68
+ list(params) {
69
+ return this.request("GET", `/v1/checkout/payment-links${toQuery(params)}`);
70
+ }
71
+ /** GET /v1/checkout/payment-links/:id */
72
+ retrieve(linkId) {
73
+ return this.request("GET", `/v1/checkout/payment-links/${encodeURIComponent(linkId)}`);
74
+ }
75
+ /** PATCH /v1/checkout/payment-links/:id */
76
+ update(linkId, params) {
77
+ return this.request("PATCH", `/v1/checkout/payment-links/${encodeURIComponent(linkId)}`, params);
78
+ }
79
+ };
58
80
 
59
81
  // src/client.ts
82
+ function validateLineItem(li) {
83
+ if ("price_id" in li) return li;
84
+ const hasHuman = li.amount != null;
85
+ const hasAtomic = li.amount_atomic != null;
86
+ if (hasHuman === hasAtomic) {
87
+ throw new Error('[BitPal] line item requires exactly one of `amount` (USD number, e.g. "29") or `amount_atomic` (raw \u03BCUSD integer, e.g. "29000000").');
88
+ }
89
+ return li;
90
+ }
60
91
  var DEFAULT_BASE_URL = "https://api.bitpal.io";
61
92
  var DEFAULT_TIMEOUT = 3e4;
62
93
  var BitPalCheckoutClient = class {
@@ -68,6 +99,8 @@ var BitPalCheckoutClient = class {
68
99
  products;
69
100
  /** PROD-LINK-3a-SDK: immutable Price 관리 — 가격 변경은 비활성화 + 새 price 생성 */
70
101
  prices;
102
+ /** PROD-LINK-4-SDK: Payment Link 관리 — 대시보드 없이 코드로 결제 링크 생성 (server-side 전용) */
103
+ paymentLinks;
71
104
  constructor(config) {
72
105
  this.apiKey = config.apiKey;
73
106
  this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
@@ -75,6 +108,7 @@ var BitPalCheckoutClient = class {
75
108
  const requester = (method, path, body) => this.request(method, path, body);
76
109
  this.products = new ProductsResource(requester);
77
110
  this.prices = new PricesResource(requester);
111
+ this.paymentLinks = new PaymentLinksResource(requester);
78
112
  }
79
113
  /* ─── 내부 HTTP ─── */
80
114
  async request(method, path, body, extraHeaders) {
@@ -107,20 +141,22 @@ var BitPalCheckoutClient = class {
107
141
  /**
108
142
  * 체크아웃 세션 생성.
109
143
  *
110
- * 모든 `line_items[].amount`는 atomic μUSDC 정수 문자열이어야 한다 ($1 = "1000000").
111
- * decimal 표기는 거부된다 — `toAtomicUSDC()` 헬퍼 사용 권장.
144
+ * `line_items[].amount` 는 사람 표기 USD 문자열("29", "0.5") — decimal 계산 불필요.
145
+ * 이미 raw μUSD 정수라면 `amount_atomic`("29000000") 사용(고급). 둘은 상호 배타.
112
146
  *
113
147
  * @example
114
- * import { BitPal, toAtomicUSDC } from '@bitpal/checkout';
148
+ * import { BitPal } from '@bitpal/checkout';
115
149
  * const bp = new BitPal('bp_test_...');
116
150
  * const { data } = await bp.checkout.createSession({
117
- * line_items: [{ name: 'Pro', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
151
+ * // amount: 사람 표기 USD("29", "0.5"). 금액은 USD 가격이라 체인/토큰 decimal 무관.
152
+ * line_items: [{ name: 'Pro', amount: '29', currency: 'USDC' }],
118
153
  * });
119
154
  * console.log(data.url); // → buyer를 redirect할 결제 페이지
120
155
  *
121
156
  * // 멀티체인 허용 — 구매자가 Base/Optimism 중 선택(하나뿐이면 자동 선택):
157
+ * // 어떤 체인·토큰이든 amount 그대로 — 서버가 발급 시 토큰 decimals 로 재스케일.
122
158
  * await bp.checkout.createSession({
123
- * line_items: [{ name: 'Pro', amount: toAtomicUSDC('29.00'), currency: 'USDC' }],
159
+ * line_items: [{ name: 'Pro', amount: '29', currency: 'USDC' }],
124
160
  * allowed_pay_chains: ['eip155:84532', 'eip155:11155420'],
125
161
  * });
126
162
  * // 단일 체인 고정은 pay_chain 사용(둘은 상호 배타).
@@ -129,10 +165,11 @@ var BitPalCheckoutClient = class {
129
165
  if (params.pay_chain && params.allowed_pay_chains && params.allowed_pay_chains.length > 0) {
130
166
  throw new Error("[BitPal] pay_chain and allowed_pay_chains are mutually exclusive \u2014 use only one.");
131
167
  }
168
+ const body = { ...params, line_items: params.line_items.map(validateLineItem) };
132
169
  const res = await this.request(
133
170
  "POST",
134
171
  "/v1/checkout/sessions",
135
- params
172
+ body
136
173
  );
137
174
  if (res.data) {
138
175
  if (res.data.checkout_url) {
@@ -162,7 +199,7 @@ var BitPalCheckoutClient = class {
162
199
  `/v1/checkout/sessions${query ? `?${query}` : ""}`
163
200
  );
164
201
  }
165
- /* ─── 비수탁 결제 (deposit-address) ─── */
202
+ /* ─── 안2 비수탁 결제 (deposit-address) ─── */
166
203
  /**
167
204
  * 공개 세션 조회 (`GET /v1/checkout/sessions/:id/public`) — 인증 불요.
168
205
  *
@@ -178,7 +215,7 @@ var BitPalCheckoutClient = class {
178
215
  /**
179
216
  * 주문별 비수탁 입금주소 발급 (`POST /v1/checkout/sessions/:id/deposit-address`).
180
217
  *
181
- * 비수탁 결제 진입점. 구매자가 자산(멀티옵션이면 chain/token)과 환불 주소를 확정하면 서버가
218
+ * 안2 결제 진입점. 구매자가 자산(멀티옵션이면 chain/token)과 환불 주소를 확정하면 서버가
182
219
  * 그 주문 전용 CREATE2 forwarder 주소를 돌려준다. 구매자는 아무 지갑/거래소에서 **정확한 금액**을
183
220
  * 그 주소로 일반 송금하면 된다(서명·연결 불필요). watcher 가 감지 → keeper 가 정산.
184
221
  *
@@ -283,26 +320,40 @@ function parseWebhookEvent(body) {
283
320
  }
284
321
 
285
322
  // src/amount.ts
286
- var USDC_DECIMALS = 6n;
287
- var USDC_SCALE = 10n ** USDC_DECIMALS;
288
- function toAtomicUSDC(decimal) {
289
- if (typeof decimal !== "string" || !/^\d+(\.\d{1,6})?$/.test(decimal)) {
290
- throw new Error(`toAtomicUSDC: invalid decimal '${decimal}' (max 6 fractional digits, no negatives)`);
323
+ function toAtomic(decimal, decimals) {
324
+ if (!Number.isInteger(decimals) || decimals < 0 || decimals > 36) {
325
+ throw new Error(`toAtomic: invalid decimals '${decimals}'`);
326
+ }
327
+ const fracPattern = decimals > 0 ? `(\\.\\d{1,${decimals}})?` : "";
328
+ if (typeof decimal !== "string" || !new RegExp(`^\\d+${fracPattern}$`).test(decimal)) {
329
+ throw new Error(`toAtomic: invalid decimal '${decimal}' (max ${decimals} fractional digits, no negatives)`);
291
330
  }
331
+ const scale = 10n ** BigInt(decimals);
292
332
  const [whole = "0", frac = ""] = decimal.split(".");
293
- const fracPadded = frac.padEnd(Number(USDC_DECIMALS), "0");
294
- return (BigInt(whole) * USDC_SCALE + BigInt(fracPadded || "0")).toString();
333
+ const fracPadded = frac.padEnd(decimals, "0");
334
+ return (BigInt(whole) * scale + BigInt(fracPadded || "0")).toString();
295
335
  }
296
- function fromAtomicUSDC(atomic) {
336
+ function fromAtomic(atomic, decimals) {
337
+ if (!Number.isInteger(decimals) || decimals < 0 || decimals > 36) {
338
+ throw new Error(`fromAtomic: invalid decimals '${decimals}'`);
339
+ }
297
340
  if (typeof atomic !== "string" || !/^\d+$/.test(atomic)) {
298
- throw new Error(`fromAtomicUSDC: invalid atomic '${atomic}' (must be non-negative integer string)`);
341
+ throw new Error(`fromAtomic: invalid atomic '${atomic}' (must be non-negative integer string)`);
299
342
  }
343
+ const scale = 10n ** BigInt(decimals);
300
344
  const big = BigInt(atomic);
301
- const whole = big / USDC_SCALE;
302
- const frac = big % USDC_SCALE;
303
- const fracStr = frac.toString().padStart(Number(USDC_DECIMALS), "0").replace(/0+$/, "");
345
+ const whole = big / scale;
346
+ const frac = big % scale;
347
+ if (decimals === 0) return `${whole}`;
348
+ const fracStr = frac.toString().padStart(decimals, "0").replace(/0+$/, "");
304
349
  return fracStr.length > 0 ? `${whole}.${fracStr.padEnd(2, "0")}` : `${whole}.00`;
305
350
  }
351
+ function toAtomicUSDC(decimal) {
352
+ return toAtomic(decimal, 6);
353
+ }
354
+ function fromAtomicUSDC(atomic) {
355
+ return fromAtomic(atomic, 6);
356
+ }
306
357
 
307
358
  // src/index.ts
308
359
  var BitPal = class {
@@ -317,11 +368,14 @@ export {
317
368
  BitPalCheckoutClient,
318
369
  BitPalError,
319
370
  CHECKOUT_WEBHOOK_EVENTS,
371
+ PaymentLinksResource,
320
372
  PricesResource,
321
373
  ProductsResource,
322
374
  WEBHOOK_HEADERS,
375
+ fromAtomic,
323
376
  fromAtomicUSDC,
324
377
  parseWebhookEvent,
378
+ toAtomic,
325
379
  toAtomicUSDC,
326
380
  verifyWebhookSignature
327
381
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitpal/checkout",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "BitPal Checkout SDK — non-custodial crypto checkout: create sessions, issue per-order deposit addresses, poll status, verify signed webhooks.",
5
5
  "license": "MIT",
6
6
  "repository": {