@klappay/types 3.8.0 → 4.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/dist/index.mjs CHANGED
@@ -7,8 +7,11 @@ import {
7
7
  NETWORK_LABELS,
8
8
  OPERATIONAL_NETWORKS,
9
9
  TOKEN_ADDRESSES,
10
- TOKEN_DECIMALS
11
- } from "./chunk-KZ3646WX.mjs";
10
+ TOKEN_DECIMALS,
11
+ TOKEN_DEPLOYMENTS,
12
+ getTokenDeployment,
13
+ isPaymentDeploymentEnabled
14
+ } from "./chunk-WKIOAEJ3.mjs";
12
15
 
13
16
  // src/errors.ts
14
17
  import { z } from "zod";
@@ -27,7 +30,7 @@ var ErrorPayloadSchema = z.object({
27
30
  // src/environment.ts
28
31
  import { z as z2 } from "zod";
29
32
  var EnvironmentSchema = z2.enum(["live", "test"]).describe(
30
- "`live` or `test`, matching the `klap_live_.../klap_test_...` prefix of the API key that created or is scoped to this resource. `live` settles on Base mainnet with real funds; `test` settles on Base Sepolia, a separate testnet \u2014 real on-chain activity, but never real money."
33
+ "`live` or `test`, matching the `klap_live_.../klap_test_...` prefix of the API key that created or is scoped to this resource. `live` uses the selected network's mainnet with real funds; `test` uses its separately configured testnet. Token contracts and availability are resolved per network/environment; a missing test deployment never falls back to live."
31
34
  );
32
35
 
33
36
  // src/api-key-scopes.ts
@@ -91,7 +94,7 @@ function paginatedSchema(itemSchema) {
91
94
  // src/tokens.ts
92
95
  import { z as z6 } from "zod";
93
96
  var TokenSchema = z6.enum(["USDC", "USDT"]).describe(
94
- `Which stablecoin the payer will send. Support depends on both \`network\` and \`environment\` \u2014 not every token/network/environment combination is deployed; today, both \`USDC\` and \`USDT\` are deployed on every operational network's \`live\` side except BNB Chain (\`${OPERATIONAL_NETWORKS.join(", ")}\`), but \`test\` coverage varies per network \u2014 Base, Optimism, and Ethereum each have a \`test\` environment (\`USDC\` only; none has an official Sepolia USDT), Arbitrum, Polygon, Avalanche, and BNB Chain have none yet (0xSplits hasn't deployed on Arbitrum Sepolia and has no Polygon, Avalanche Fuji, or BNB testnet support at all). An unconfigured combination is rejected with \`422 token_not_supported\`, not silently accepted. **BNB Chain's \`USDC\` address is Binance-Peg USDC, not an official Circle deployment** \u2014 Circle does not issue native USDC on BNB Chain at all; this is a Binance-custodied, 1:1-pegged BEP-20 token, a materially different trust model than every other \`TOKEN_ADDRESSES\` entry (all verified directly against their real issuer). Accepted at the payer's own risk \u2014 Klappay does not verify or guarantee Binance's collateral backing it. \`USDT\` on BNB Chain is Tether's own official issuance, same trust model as everywhere else. More tokens/networks are expected to be added over time \u2014 check \`TOKEN_ADDRESSES\` in \`@klappay/types\` (or a future \`GET /v1/networks\` capabilities endpoint) for the exact current matrix rather than assuming full coverage.`
97
+ "Which stablecoin the payer will send. Availability depends on `network` and `environment`; check `GET /v1/networks` before creating a charge. Unconfigured or disabled pairs are rejected with `422 token_not_supported`. Base, Optimism, and Ethereum have USDC test deployments; no test USDT is configured. The catalog includes both BNB Chain tokens for historical interpretation, but payments with either are currently disabled. Both configured BNB contracts are Binance-Peg tokens with 18 decimals; the other configured deployments use 6. Binance-Peg tokens carry Binance custody/backing risk and must not be represented as direct Circle/Tether issuance. Resolve address and decimals together with `getTokenDeployment`; a catalog entry alone does not imply payment availability."
95
98
  );
96
99
 
97
100
  // src/alt-tokens.ts
@@ -116,7 +119,7 @@ function listSwapAlternatives(networks) {
116
119
  }
117
120
 
118
121
  // src/charges.ts
119
- import { z as z10 } from "zod";
122
+ import { z as z11 } from "zod";
120
123
 
121
124
  // src/checkout-metadata.ts
122
125
  import { z as z8 } from "zod";
@@ -157,38 +160,44 @@ var RefundEscrowRequestSchema = z9.object({
157
160
  )
158
161
  });
159
162
 
163
+ // src/exact-amount.ts
164
+ import { z as z10 } from "zod";
165
+ var ExactAmountSchema = z10.string().regex(/^(0|[1-9]\d*)(?:\.\d{1,18})?$(?!\s)/).describe(
166
+ "Nonnegative amount in whole currency/token units, as a decimal string with at most 18 fractional digits and no scientific notation."
167
+ );
168
+
160
169
  // src/charges.ts
161
- var ChargeStatusSchema = z10.enum(["pending", "partially_paid", "confirmed", "expired", "underpaid"]).describe(
170
+ var ChargeStatusSchema = z11.enum(["pending", "partially_paid", "confirmed", "expired", "underpaid"]).describe(
162
171
  "Payment progress, from the payer side. `pending`: created, nothing received yet. `partially_paid`: some funds received, less than `amount`. `confirmed`: full amount received (or more \u2014 see `isOverpaid`). `expired`: `expiresAt` passed with zero funds received. `underpaid`: `expiresAt` passed while `partially_paid`. Every status is reached automatically, on its own timeline \u2014 there is no merchant-initiated cancellation. This never reflects whether funds actually reached the merchant \u2014 see `settlementStatus` for that."
163
172
  );
164
- var SettlementStatusSchema = z10.enum(["pending", "completed", "failed"]).describe(
173
+ var SettlementStatusSchema = z11.enum(["pending", "completed", "failed"]).describe(
165
174
  "Progress of the payout to the merchant's wallet, a separate step from `status` \u2014 `status: confirmed` only means the payment was detected on-chain, not that the merchant has been paid yet. `pending`: payment detected, payout not yet attempted. `completed`: the merchant's wallet has the funds. `failed`: the payout attempt failed and retries were exhausted (rare; contact support). `null` on the parent `Charge` means no payout has been attempted yet \u2014 nothing has been received, or the charge is still in progress."
166
175
  );
167
- var ChargeFeePayerSchema = z10.enum(["merchant", "payer"]).describe(
176
+ var ChargeFeePayerSchema = z11.enum(["merchant", "payer"]).describe(
168
177
  "Who ends up covering Klappay's `feePercent`. `merchant` (default): `amount` is exactly what you asked for, and Klappay's fee is deducted from your own payout \u2014 you net `amount * (1 - feePercent / 100)`. `payer` : `amount` is grossed up at creation time so that, after the same fee deduction, you still net the amount you originally requested \u2014 the payer sees and sends the larger, fee-inclusive total. Frozen at creation like every other fee input; does not change how `feeAmount`/`merchantAmount` are computed on read, only what `amount` was set to in the first place."
169
178
  );
170
179
  var CHARGE_EXPIRES_IN_MIN_SECONDS = 60;
171
180
  var CHARGE_EXPIRES_IN_MAX_SECONDS = 3600;
172
181
  var CHARGE_ACCEPTED_PAYMENTS_MAX = 14;
173
- var AcceptedPaymentSchema = z10.object({
182
+ var AcceptedPaymentSchema = z11.object({
174
183
  token: TokenSchema,
175
184
  network: NetworkSchema
176
185
  });
177
- var AcceptedPaymentsSchema = z10.array(AcceptedPaymentSchema).min(1, "At least one accepted payment is required.").max(CHARGE_ACCEPTED_PAYMENTS_MAX).superRefine((pairs, ctx) => {
186
+ var AcceptedPaymentsSchema = z11.array(AcceptedPaymentSchema).min(1, "At least one accepted payment is required.").max(CHARGE_ACCEPTED_PAYMENTS_MAX).superRefine((pairs, ctx) => {
178
187
  const seen = /* @__PURE__ */ new Set();
179
188
  pairs.forEach((pair, index) => {
180
189
  const key = `${pair.token}:${pair.network}`;
181
190
  if (seen.has(key)) {
182
191
  ctx.addIssue({
183
- code: z10.ZodIssueCode.custom,
192
+ code: z11.ZodIssueCode.custom,
184
193
  message: `Duplicate accepted payment: ${pair.token} on ${pair.network}.`,
185
194
  path: [index]
186
195
  });
187
196
  }
188
197
  seen.add(key);
189
- if (!OPERATIONAL_NETWORKS.includes(pair.network)) {
198
+ if (!OPERATIONAL_NETWORKS.some((network) => network === pair.network)) {
190
199
  ctx.addIssue({
191
- code: z10.ZodIssueCode.custom,
200
+ code: z11.ZodIssueCode.custom,
192
201
  message: `Network "${pair.network}" isn't live yet \u2014 only ${OPERATIONAL_NETWORKS.join(", ")} today.`,
193
202
  path: [index, "network"]
194
203
  });
@@ -198,32 +207,32 @@ var AcceptedPaymentsSchema = z10.array(AcceptedPaymentSchema).min(1, "At least o
198
207
  `Every \`(token, network)\` pair the payer is allowed to pay with \u2014 at least one, up to ${CHARGE_ACCEPTED_PAYMENTS_MAX}. This list is also the only restriction knob: the payer can use any combination of the pairs listed here, and every transfer on one of them is credited and sums toward the charge total (see \`paidWith\`) \u2014 e.g. a charge accepting USDC and USDT can be confirmed by $9 in USDC plus $1 in USDT, or by USDC arriving on two different accepted networks. To require payment in one specific token on one specific network, list only that single pair \u2014 a transfer on any pair not in this list is still recorded (for audit) but never credited. Each network must be live (see \`GET /v1/networks\` for the current matrix) \u2014 an unconfigured \`(token, network)\` combination for your environment is rejected with \`422 token_not_supported\`.`
199
208
  );
200
209
  var CHARGE_SPLIT_RECIPIENTS_MAX = 5;
201
- var SplitRecipientSchema = z10.object({
202
- address: z10.string().regex(/^0x[0-9a-fA-F]{40}$/, "must be a 20-byte hex address").describe("EVM address to send a slice of this charge to."),
203
- percent: z10.number().positive().max(100).describe(
210
+ var SplitRecipientSchema = z11.object({
211
+ address: z11.string().regex(/^0x[0-9a-fA-F]{40}$/, "must be a 20-byte hex address").describe("EVM address to send a slice of this charge to."),
212
+ percent: z11.number().positive().max(100).describe(
204
213
  "Percent of *your own* net share (i.e. of `100 - feePercent`, not of the charge's gross `amount`) to route to this address instead of your own payout wallet. Klappay's fee is computed on the gross amount first and is never diluted by how you choose to split what's left \u2014 see `docs/payments.md`'s \"Settling the payout\" section for the exact math."
205
214
  ),
206
- label: z10.string().min(1).max(64).optional().describe(
215
+ label: z11.string().min(1).max(64).optional().describe(
207
216
  'Free-form label for your own bookkeeping (e.g. `"supplier"`, `"sales rep"`) \u2014 echoed back unchanged, never interpreted by Klappay.'
208
217
  )
209
218
  });
210
- var SplitRecipientInputSchema = z10.object({
211
- recipientId: z10.string().describe(
219
+ var SplitRecipientInputSchema = z11.object({
220
+ recipientId: z11.string().describe(
212
221
  "id of a `Recipient` you already registered via `POST /v1/recipients` (not a raw address) \u2014 see `recipients:write`/`charges:split_write` scopes. A leaked `charges:write`-only key can never redirect payout to a brand new address this way, only reference one already trusted."
213
222
  ),
214
- percent: z10.number().positive().max(100).describe(
223
+ percent: z11.number().positive().max(100).describe(
215
224
  "Percent of *your own* net share (i.e. of `100 - feePercent`, not of the charge's gross `amount`) to route to this recipient instead of your own payout wallet. Klappay's fee is computed on the gross amount first and is never diluted by how you choose to split what's left \u2014 see `docs/payments.md`'s \"Settling the payout\" section for the exact math."
216
225
  ),
217
- label: z10.string().min(1).max(64).optional().describe(
226
+ label: z11.string().min(1).max(64).optional().describe(
218
227
  'Free-form label for your own bookkeeping (e.g. `"supplier"`, `"sales rep"`) \u2014 echoed back unchanged, never interpreted by Klappay. Independent of the label the recipient was registered with.'
219
228
  )
220
229
  });
221
- var SplitRecipientsInputSchema = z10.array(SplitRecipientInputSchema).max(CHARGE_SPLIT_RECIPIENTS_MAX).superRefine((recipients, ctx) => {
230
+ var SplitRecipientsInputSchema = z11.array(SplitRecipientInputSchema).max(CHARGE_SPLIT_RECIPIENTS_MAX).superRefine((recipients, ctx) => {
222
231
  const seen = /* @__PURE__ */ new Set();
223
232
  recipients.forEach((recipient, index) => {
224
233
  if (seen.has(recipient.recipientId)) {
225
234
  ctx.addIssue({
226
- code: z10.ZodIssueCode.custom,
235
+ code: z11.ZodIssueCode.custom,
227
236
  message: `Duplicate split recipientId: ${recipient.recipientId}.`,
228
237
  path: [index, "recipientId"]
229
238
  });
@@ -234,27 +243,27 @@ var SplitRecipientsInputSchema = z10.array(SplitRecipientInputSchema).max(CHARGE
234
243
  `Optional extra recipients for this charge's split \u2014 e.g. a supplier or the sales rep who closed the deal \u2014 up to ${CHARGE_SPLIT_RECIPIENTS_MAX}, each referenced by \`recipientId\` (see \`POST /v1/recipients\`), never a raw address. Requires the \`charges:split_write\` scope in addition to \`charges:write\`. Frozen at creation exactly like everything else that shapes the split address; cannot be changed afterward. The sum of every \`percent\` here must fit within \`100 - feePercent\` (your own net share) \u2014 a request that doesn't is rejected with \`422 split_recipients_exceed_available_percent\`.`
235
244
  );
236
245
  var CHARGE_AMOUNT_MAX = 999999999999;
237
- var CreateChargeSchema = z10.object({
238
- amount: z10.number().positive().max(CHARGE_AMOUNT_MAX).describe(
246
+ var CreateChargeSchema = z11.object({
247
+ amount: z11.number().positive().max(CHARGE_AMOUNT_MAX).describe(
239
248
  "Amount to charge, in `currency` units (e.g. `49.9` = $49.90) \u2014 up to 6 decimal places; anything more precise is silently truncated. Required \u2014 every charge has a target amount, the first credited transfer that reaches it confirms the charge. With `feePayer: 'payer'` (see below), this is your own desired net amount, not the total the payer ends up sending \u2014 the response's `amount` is grossed up to cover `feePercent`, while `merchantAmount` on the response echoes back this exact value."
240
249
  ),
241
250
  feePayer: ChargeFeePayerSchema.optional().default("merchant"),
242
- currency: z10.literal("USD").default("USD").describe("Always `USD` today \u2014 the only supported currency."),
251
+ currency: z11.literal("USD").default("USD").describe("Always `USD` today \u2014 the only supported currency."),
243
252
  acceptedPayments: AcceptedPaymentsSchema,
244
- expiresIn: z10.number().int().min(CHARGE_EXPIRES_IN_MIN_SECONDS).max(CHARGE_EXPIRES_IN_MAX_SECONDS).describe(
253
+ expiresIn: z11.number().int().min(CHARGE_EXPIRES_IN_MIN_SECONDS).max(CHARGE_EXPIRES_IN_MAX_SECONDS).describe(
245
254
  "Seconds, not minutes or milliseconds \u2014 how long the charge stays open before it expires. Required, min 60, max 3600 (60 minutes) \u2014 sized off the slowest chain Klappay supports today (Ethereum mainnet, where a safely-confirmed transfer takes up to ~15 minutes), leaving real margin for payer-side delay (gas spikes, wallet friction) on top of that. Cannot be extended or shortened after creation."
246
255
  ),
247
- idempotencyKey: z10.string().min(1).max(255).optional().describe(
256
+ idempotencyKey: z11.string().min(1).max(255).optional().describe(
248
257
  "Scoped to your tenant. Replaying the same key with the exact same request body returns the original charge unchanged instead of creating a duplicate \u2014 safe to retry a request after a timeout without double-charging. Reusing the same key with a different body (including a different `escrow` config) is rejected with `409 idempotency_key_reused`, never silently returned as the original charge."
249
258
  ),
250
- externalRef: z10.string().min(1).max(255).optional().describe(
259
+ externalRef: z11.string().min(1).max(255).optional().describe(
251
260
  "An opaque correlation id from your own system (e.g. an order id) \u2014 echoed back on the charge and in every webhook payload. Not interpreted or validated by Klappay."
252
261
  ),
253
- source: z10.string().min(1).max(64).optional().describe(
262
+ source: z11.string().min(1).max(64).optional().describe(
254
263
  'Free-form label for what created this charge (e.g. `"checkout"`, `"invoice"`) \u2014 useful if you create charges from more than one flow and want to tell them apart later. Not a fixed enum; use whatever values make sense to you.'
255
264
  ),
256
265
  metadata: MetadataWithKlappaySchema.optional(),
257
- redirectUrl: z10.string().url().refine((value) => /^https?:\/\//.test(value), "must use http or https").optional().describe(
266
+ redirectUrl: z11.string().url().refine((value) => /^https?:\/\//.test(value), "must use http or https").optional().describe(
258
267
  "Where to send the payer once this charge resolves, if you use Klappay's hosted checkout page (see `checkoutUrl` on the read shape) \u2014 ignored otherwise. Must be `http(s)` \u2014 a browser will navigate here, so `javascript:`/`data:` and other non-navigational schemes are rejected. Otherwise not validated beyond being well-formed; what happens at that destination is yours to build."
259
268
  ),
260
269
  splitRecipients: SplitRecipientsInputSchema.optional(),
@@ -262,77 +271,86 @@ var CreateChargeSchema = z10.object({
262
271
  "Configure this charge as an escrow instead of a normal payment. Funds land in a dedicated, non-custodial Safe (not the usual split address) and only `releaserAddress` (or, if omitted, your API key's own `payoutAddress`) can ever release them \u2014 via `POST /v1/charges/{id}/release`, signed on their end, never something Klappay can trigger or redirect. Omit this field entirely for a normal charge."
263
272
  )
264
273
  });
265
- var ChargeSchema = z10.object({
266
- id: z10.string().describe("Klappay-generated id, e.g. `ch_...`. Use this to look up the charge later."),
267
- amount: z10.number().describe(
268
- "The exact total the payer must send, in `currency` units (up to 6 decimal places). With `feePayer: 'merchant'` (the default) this is exactly what you requested at creation. With `feePayer: 'payer'` this is grossed up to cover `feePercent` \u2014 see `merchantAmount` for what you requested/will actually net."
274
+ var ChargeSchema = z11.object({
275
+ id: z11.string().describe("Klappay-generated id, e.g. `ch_...`. Use this to look up the charge later."),
276
+ amount: z11.number().describe(
277
+ "The total the payer must send, in `currency` units (up to 6 decimal places). This legacy JSON number can lose precision; use `amountExact` for calculations and payment preparation. With `feePayer: 'merchant'` (the default) this is what you requested at creation. With `feePayer: 'payer'` this is grossed up to cover `feePercent` \u2014 see `merchantAmount` for what you requested/will actually net."
278
+ ),
279
+ amountExact: ExactAmountSchema.regex(/^(0|[1-9]\d*)(?:\.\d{1,6})?$/).optional().describe(
280
+ 'Exact total the payer must send, in `currency` units, as a nonnegative decimal string with at most 6 fractional digits and no scientific notation (e.g. `"100.000001"`). Use this instead of `amount` for arithmetic. Optional for compatibility with older API responses.'
269
281
  ),
270
282
  feePayer: ChargeFeePayerSchema,
271
- feePercent: z10.number().describe(
283
+ feePercent: z11.number().describe(
272
284
  "Klappay's fee for this charge, as a percent of `amount` (e.g. `2` = 2%) \u2014 includes any escrow surcharge if this charge is an escrow. Frozen at creation; see `feeAmount`/`merchantAmount` for the actual amounts this works out to."
273
285
  ),
274
- feeAmount: z10.number().describe("`amount * feePercent / 100`, in `currency` units \u2014 Klappay's cut of this charge."),
275
- merchantAmount: z10.number().describe(
286
+ feeAmount: z11.number().describe("`amount * feePercent / 100`, in `currency` units \u2014 Klappay's cut of this charge."),
287
+ merchantAmount: z11.number().describe(
276
288
  "`amount - feeAmount`, in `currency` units \u2014 what you actually net once the payout settles, regardless of `feePayer` (this is always what the split delivers to you; `feePayer` only affects what `amount` was set to at creation)."
277
289
  ),
278
- amountReceived: z10.number().nullable().describe(
279
- "Cumulative amount actually received on-chain so far, in `currency` units (up to 6 decimal places). `null` until the first transfer arrives. Can exceed `amount` \u2014 see `isOverpaid`."
290
+ amountReceived: z11.number().nullable().describe(
291
+ "Cumulative amount received on-chain so far, in `currency` units. This legacy JSON number can lose precision; use `amountReceivedExact` for arithmetic with up to 18 fractional digits. `null` until the first transfer arrives. Can exceed `amount` \u2014 see `isOverpaid`."
292
+ ),
293
+ amountReceivedExact: ExactAmountSchema.nullable().optional().describe(
294
+ 'Exact cumulative amount received on-chain, in `currency` units, as a nonnegative decimal string with at most 18 fractional digits and no scientific notation (e.g. `"0.0000000001"`). `null` until the first transfer arrives. Can exceed `amountExact`. Optional for compatibility with older API responses.'
295
+ ),
296
+ paymentUnavailable: z11.boolean().optional().describe(
297
+ "When `true`, payment processing for this charge is temporarily unavailable. Do not offer payment instructions, request another transfer, or fulfill from its monetary/status fields until availability is restored. The charge retains its existing business status. Optional for compatibility with older API responses."
280
298
  ),
281
- isOverpaid: z10.boolean().describe(
299
+ isOverpaid: z11.boolean().describe(
282
300
  "`true` if `amountReceived` ended up greater than `amount`. Klappay never refunds the difference automatically \u2014 see the docs for why."
283
301
  ),
284
- currency: z10.string().describe("Always `USD` today \u2014 the only supported currency."),
285
- acceptedPayments: z10.array(AcceptedPaymentSchema).describe(
302
+ currency: z11.string().describe("Always `USD` today \u2014 the only supported currency."),
303
+ acceptedPayments: z11.array(AcceptedPaymentSchema).describe(
286
304
  "Every `(token, network)` pair this charge was configured to accept, unchanged after creation."
287
305
  ),
288
- paidWith: z10.array(AcceptedPaymentSchema).describe(
306
+ paidWith: z11.array(AcceptedPaymentSchema).describe(
289
307
  "Every distinct `(token, network)` pair that has actually contributed a credited transfer so far \u2014 empty until the first one arrives. Can hold more than one entry: a charge accepting several pairs can be paid across a combination of them, and every entry here sums toward `amountReceived`."
290
308
  ),
291
- swapAlternatives: z10.array(SwapAlternativeSchema).describe(
309
+ swapAlternatives: z11.array(SwapAlternativeSchema).describe(
292
310
  "Every `(token, network)` pair the payer can pay with instead, via `POST /v1/charges/{id}/quote` \u2014 derived from the networks in `acceptedPayments` (e.g. a charge accepting USDC on both Base and Optimism lists `ETH` on Base and `ETH` on Optimism separately, since they're different networks the payer has to choose between, not one merged option). Pass an entry's `token`/`network` straight through as `inputToken`/`inputNetwork`. Recomputed on every read against Klappay's current trusted list, not frozen at creation \u2014 empty if this charge's networks have no trusted alt-token, if swap-to-pay isn't configured on this deployment, or if `environment` is `test` (0x, who powers the swap, has no testnet support at all \u2014 `POST /v1/charges/{id}/quote` always rejects a test-environment charge with `422 swap_test_environment_unsupported`)."
293
311
  ),
294
- address: z10.string().describe(
312
+ address: z11.string().describe(
295
313
  "The on-chain address the payer must send funds to \u2014 identical across every accepted network (0xSplits addresses are chain-agnostic). Unique per charge, predicted at creation time \u2014 funds sent here go directly to the merchant, Klappay never custodies them."
296
314
  ),
297
315
  status: ChargeStatusSchema,
298
316
  settlementStatus: SettlementStatusSchema.nullable(),
299
317
  environment: EnvironmentSchema,
300
- apiKeyId: z10.string().nullable().describe(
318
+ apiKeyId: z11.string().nullable().describe(
301
319
  "Which of your API keys created this charge. `null` for a charge created before this field existed."
302
320
  ),
303
- txHash: z10.string().nullable().describe(
321
+ txHash: z11.string().nullable().describe(
304
322
  "Transaction hash of the most recent transfer detected for this charge. `null` until a payment is detected."
305
323
  ),
306
- externalRef: z10.string().nullable(),
307
- source: z10.string().nullable(),
324
+ externalRef: z11.string().nullable(),
325
+ source: z11.string().nullable(),
308
326
  metadata: MetadataWithKlappaySchema.nullable(),
309
- redirectUrl: z10.string().nullable().describe("Echoes the `redirectUrl` set at creation, if any. `null` if none was set."),
310
- checkoutUrl: z10.string().nullable().describe(
327
+ redirectUrl: z11.string().nullable().describe("Echoes the `redirectUrl` set at creation, if any. `null` if none was set."),
328
+ checkoutUrl: z11.string().nullable().describe(
311
329
  "Link to Klappay's hosted checkout page for this charge. `null` if this deployment has no hosted checkout configured \u2014 build your own payment UI from `address`/`acceptedPayments` instead."
312
330
  ),
313
- splitRecipients: z10.array(SplitRecipientSchema).describe("Echoes whatever extra split recipients were set at creation \u2014 empty array if none."),
314
- createdAt: z10.string().datetime(),
315
- expiresAt: z10.string().datetime().describe(
331
+ splitRecipients: z11.array(SplitRecipientSchema).describe("Echoes whatever extra split recipients were set at creation \u2014 empty array if none."),
332
+ createdAt: z11.string().datetime(),
333
+ expiresAt: z11.string().datetime().describe(
316
334
  "When this charge stops accepting payment, if still `pending`/`partially_paid` by then."
317
335
  ),
318
- confirmedAt: z10.string().datetime().nullable().describe("When `status` first reached `confirmed`. `null` until then."),
319
- settledAt: z10.string().datetime().nullable().describe(
336
+ confirmedAt: z11.string().datetime().nullable().describe("When `status` first reached `confirmed`. `null` until then."),
337
+ settledAt: z11.string().datetime().nullable().describe(
320
338
  "When `settlementStatus` first reached `completed` \u2014 the merchant's wallet actually has the funds. `null` until then, including while `settlementStatus` is `pending`/`failed`."
321
339
  ),
322
- lastActivityAt: z10.string().datetime().describe(
340
+ lastActivityAt: z11.string().datetime().describe(
323
341
  "When a transfer was last credited toward this charge, or `createdAt` if none has arrived yet."
324
342
  ),
325
- escrow: z10.object({
326
- releaserAddress: z10.string().describe("The only address that can ever release this escrow \u2014 never Klappay."),
327
- releasedAt: z10.string().datetime().nullable().describe("When the release actually executed on-chain. `null` until then."),
328
- refundedAt: z10.string().datetime().nullable().describe(
343
+ escrow: z11.object({
344
+ releaserAddress: z11.string().describe("The only address that can ever release this escrow \u2014 never Klappay."),
345
+ releasedAt: z11.string().datetime().nullable().describe("When the release actually executed on-chain. `null` until then."),
346
+ refundedAt: z11.string().datetime().nullable().describe(
329
347
  "When the refund actually executed on-chain. `null` until then. Mutually exclusive with `releasedAt` \u2014 an escrow can only ever be released or refunded once, never both."
330
348
  )
331
349
  }).nullable().describe(
332
350
  "Present only when this charge was created as an escrow (see `escrow` on the create request) \u2014 `null` for a normal charge."
333
351
  )
334
352
  });
335
- var ListChargesSchema = z10.object({
353
+ var ListChargesSchema = z11.object({
336
354
  status: ChargeStatusSchema.optional(),
337
355
  token: TokenSchema.optional().describe(
338
356
  "Filters on `paidWith.token` \u2014 the pair actually paid, not accepted."
@@ -341,13 +359,13 @@ var ListChargesSchema = z10.object({
341
359
  "Filters on `paidWith.network` \u2014 the pair actually paid, not accepted."
342
360
  ),
343
361
  environment: EnvironmentSchema.optional(),
344
- since: z10.string().datetime().optional().describe(
362
+ since: z11.string().datetime().optional().describe(
345
363
  "Only return charges created at or after this timestamp (filters on `createdAt`, not on when the status last changed). If polling as a fallback for missed webhooks, use a window at least as wide as the longest `expiresIn` your charges use, or you can miss a long-lived charge that changed status outside a narrower window."
346
364
  ),
347
- isOverpaid: z10.enum(["true", "false"]).transform((v) => v === "true").optional()
365
+ isOverpaid: z11.enum(["true", "false"]).transform((v) => v === "true").optional()
348
366
  }).extend(PaginationQuerySchema.shape);
349
367
  var PaginatedChargesSchema = paginatedSchema(ChargeSchema);
350
- var GetChargeQrCodeQuerySchema = z10.object({
368
+ var GetChargeQrCodeQuerySchema = z11.object({
351
369
  token: TokenSchema.optional().describe(
352
370
  "Which accepted `(token, network)` pair to encode in the QR \u2014 required if `acceptedPayments` has more than one pair, since there is no single unambiguous default to fall back to. Ignored (and unnecessary) when the charge accepts exactly one pair."
353
371
  ),
@@ -355,19 +373,19 @@ var GetChargeQrCodeQuerySchema = z10.object({
355
373
  });
356
374
 
357
375
  // src/charge-check.ts
358
- import { z as z12 } from "zod";
376
+ import { z as z13 } from "zod";
359
377
 
360
378
  // src/confirmation-progress.ts
361
- import { z as z11 } from "zod";
362
- var ConfirmationProgressSchema = z11.object({
379
+ import { z as z12 } from "zod";
380
+ var ConfirmationProgressSchema = z12.object({
363
381
  network: NetworkSchema.describe("Which network the transfer was seen on."),
364
- blocksSeen: z11.number().int().min(0).describe(
382
+ blocksSeen: z12.number().int().min(0).describe(
365
383
  "How many blocks have passed since the transfer's own block, as of this update \u2014 a raw block count, not seconds. Grows toward `blocksRequired` as the network's blocks keep arriving."
366
384
  ),
367
- blocksRequired: z11.number().int().min(1).describe(
385
+ blocksRequired: z12.number().int().min(1).describe(
368
386
  "This network's minimum confirmation depth (a fixed, per-network constant) \u2014 the transfer is only credited once `blocksSeen` reaches this value."
369
387
  ),
370
- percent: z11.number().int().min(0).max(99).describe(
388
+ percent: z12.number().int().min(0).max(99).describe(
371
389
  '`blocksSeen`/`blocksRequired` as a rounded-down 0-99 percentage, for a progress bar. Never reaches 100 by construction \u2014 once a transfer is deep enough it is credited immediately and this stops being reported at all (the charge event itself is the "done" signal).'
372
390
  )
373
391
  }).describe(
@@ -375,8 +393,8 @@ var ConfirmationProgressSchema = z11.object({
375
393
  );
376
394
 
377
395
  // src/charge-check.ts
378
- var CheckChargeRequestSchema = z12.object({
379
- txHash: z12.string().regex(/^0x[0-9a-fA-F]{64}$/, "must be a 32-byte transaction hash").optional().describe(
396
+ var CheckChargeRequestSchema = z13.object({
397
+ txHash: z13.string().regex(/^0x[0-9a-fA-F]{64}$/, "must be a 32-byte transaction hash").optional().describe(
380
398
  "The on-chain transaction hash to verify directly, if you already have it \u2014 e.g. right after a swap-to-pay or wallet-connect transaction is sent. Costs a single RPC call instead of scanning a block range, so the check resolves faster and cheaper. Omit to fall back to scanning recent transfers to this charge's address, the same lookup the background reconciliation pass runs. Never trusted at face value \u2014 whatever this transaction actually contains on-chain is what gets credited, regardless of any amount/token implied elsewhere."
381
399
  ),
382
400
  network: NetworkSchema.optional().describe(
@@ -386,7 +404,7 @@ var CheckChargeRequestSchema = z12.object({
386
404
  message: "`txHash` and `network` must be provided together, or both omitted"
387
405
  });
388
406
  var CheckChargeResponseSchema = ChargeSchema.extend({
389
- transactionSender: z12.string().nullable().describe(
407
+ transactionSender: z13.string().nullable().describe(
390
408
  "The `txHash` transaction's own sender (`from`) \u2014 who actually signed and submitted it on-chain, which stays the payer's own wallet even when the transaction swaps through a router/aggregator on the way to paying, unlike the credited transfer's `from` (which can be the router/pool contract, not the payer). `null` unless `txHash`/`network` was passed in the request and a successful receipt was found for it \u2014 a hint-less background scan, an unaccepted network, or a not-found/reverted transaction all leave this `null`."
391
409
  ),
392
410
  confirmationProgress: ConfirmationProgressSchema.nullable().describe(
@@ -395,61 +413,61 @@ var CheckChargeResponseSchema = ChargeSchema.extend({
395
413
  });
396
414
 
397
415
  // src/distributions.ts
398
- import { z as z13 } from "zod";
399
- var SplitDistributionStatusSchema = z13.enum(["pending", "processing", "completed", "failed"]).describe(
416
+ import { z as z14 } from "zod";
417
+ var SplitDistributionStatusSchema = z14.enum(["pending", "processing", "completed", "failed"]).describe(
400
418
  "Status of one payout attempt to the merchant, for a single `(token, network)` pair \u2014 a charge that settles across more than one pair has one of these per pair. `pending`: queued, not yet claimed by a distributor. `processing`: a distributor (Klappay's own worker, or anyone racing to call `distribute()` first, see `PendingDistributionSchema`) has claimed it and is submitting the on-chain transaction. `completed`: the merchant's wallet has the funds. `failed`: every automatic retry was exhausted."
401
419
  );
402
- var PendingDistributionRecipientSchema = z13.object({
403
- address: z13.string().describe("On-chain recipient address."),
404
- percentAllocation: z13.number().describe("This recipient's share of the split, as a percentage (e.g. `99.0991` = 99.0991%).")
420
+ var PendingDistributionRecipientSchema = z14.object({
421
+ address: z14.string().describe("On-chain recipient address."),
422
+ percentAllocation: z14.number().describe("This recipient's share of the split, as a percentage (e.g. `99.0991` = 99.0991%).")
405
423
  });
406
- var PendingDistributionSchema = z13.object({
407
- splitAddress: z13.string().describe("The on-chain 0xSplits address to call `distribute()` on."),
424
+ var PendingDistributionSchema = z14.object({
425
+ splitAddress: z14.string().describe("The on-chain 0xSplits address to call `distribute()` on."),
408
426
  network: NetworkSchema,
409
427
  token: TokenSchema,
410
- recipients: z13.array(PendingDistributionRecipientSchema).describe(
428
+ recipients: z14.array(PendingDistributionRecipientSchema).describe(
411
429
  "The exact recipient list to pass to `distribute()` \u2014 the split contract only stores a hash of this config, so the caller must supply the identical array to prove it matches. Always present, never reconstructed from partial data."
412
430
  ),
413
- distributorFeePercent: z13.number().describe(
431
+ distributorFeePercent: z14.number().describe(
414
432
  "Percentage of the split balance paid to whoever calls `distribute()` first (e.g. `0.1` = 0.1%). Frozen at charge creation, same for every distribution today."
415
433
  ),
416
- estimatedRewardAmount: z13.number().describe(
434
+ estimatedRewardAmount: z14.number().describe(
417
435
  "Estimate only, in the charge's `currency` units, based on the amount Klappay detected on-chain \u2014 not a live read of the split's current balance. Read the balance yourself before submitting a transaction; a stale estimate is harmless (see the docs), never a reason to skip that check."
418
436
  ),
419
- availableSince: z13.string().datetime().describe("When this distribution entered its grace period."),
420
- graceEndsAt: z13.string().datetime().describe(
437
+ availableSince: z14.string().datetime().describe("When this distribution entered its grace period."),
438
+ graceEndsAt: z14.string().datetime().describe(
421
439
  "When Klappay's own worker may claim this distribution. Racing to call `distribute()` after this timestamp is possible but increasingly likely to lose to the worker."
422
440
  )
423
441
  });
424
442
  var PaginatedPendingDistributionsSchema = paginatedSchema(PendingDistributionSchema);
425
- var ListenPendingDistributionsQuerySchema = z13.object({
426
- limit: z13.coerce.number().int().min(0).max(PAGINATION_LIMIT_MAX).default(0).describe(
443
+ var ListenPendingDistributionsQuerySchema = z14.object({
444
+ limit: z14.coerce.number().int().min(0).max(PAGINATION_LIMIT_MAX).default(0).describe(
427
445
  "How many currently-claimable distributions to emit as an initial snapshot right after connecting \u2014 each as a synthetic `distribution.available` event \u2014 before continuing with real-time deltas. `0` (the default, same as omitting it) sends no snapshot at all, matching this endpoint's original behavior: connect first, then call `GET /v1/distributions/pending` yourself to bootstrap. Not a page \u2014 there is no cursor for this snapshot, so if more than `limit` are claimable at connect time, the excess is simply not sent; call `GET /v1/distributions/pending` directly for a complete, paginated listing."
428
446
  )
429
447
  });
430
- var PendingDistributionEventSchema = z13.discriminatedUnion("type", [
431
- z13.object({
432
- type: z13.literal("distribution.available"),
448
+ var PendingDistributionEventSchema = z14.discriminatedUnion("type", [
449
+ z14.object({
450
+ type: z14.literal("distribution.available"),
433
451
  distribution: PendingDistributionSchema
434
452
  }),
435
- z13.object({
436
- type: z13.literal("distribution.claimed"),
437
- splitAddress: z13.string().describe("No longer claimable \u2014 either settled by someone, or picked up by the worker.")
453
+ z14.object({
454
+ type: z14.literal("distribution.claimed"),
455
+ splitAddress: z14.string().describe("No longer claimable \u2014 either settled by someone, or picked up by the worker.")
438
456
  })
439
457
  ]);
440
458
 
441
459
  // src/metrics.ts
442
- import { z as z14 } from "zod";
443
- var MetricsResourceSchema = z14.enum(["charges", "transactions", "distributions"]).describe(
460
+ import { z as z15 } from "zod";
461
+ var MetricsResourceSchema = z15.enum(["charges", "transactions", "distributions"]).describe(
444
462
  "Which underlying dataset to query. `charges`: one row per charge. `transactions`: one row per detected on-chain transfer \u2014 a charge paid in installments has more than one. `distributions`: one row per payout attempt to the merchant, one per `(token, network)` pair a charge settled across."
445
463
  );
446
- var MetricsAggregationSchema = z14.enum(["count", "sum", "avg", "min", "max"]).describe(
464
+ var MetricsAggregationSchema = z15.enum(["count", "sum", "avg", "min", "max"]).describe(
447
465
  "`count` counts matching rows and never takes `field`. `sum`/`avg`/`min`/`max` require `field` to be set to one of the resource\u2019s numeric fields."
448
466
  );
449
- var MetricsFilterOperatorSchema = z14.enum(["eq", "neq", "in", "gt", "gte", "lt", "lte"]).describe(
467
+ var MetricsFilterOperatorSchema = z15.enum(["eq", "neq", "in", "gt", "gte", "lt", "lte"]).describe(
450
468
  "`in` expects an array value (max 50 entries); every other operator expects a single scalar."
451
469
  );
452
- var MetricsDateGranularitySchema = z14.enum(["day", "week", "month", "year"]).describe(
470
+ var MetricsDateGranularitySchema = z15.enum(["day", "week", "month", "year"]).describe(
453
471
  "Bucket width for a `date_bucket` `groupBy` entry \u2014 Postgres `date_trunc` semantics (UTC)."
454
472
  );
455
473
  var metricsQueryEnvironmentSchema = EnvironmentSchema.describe(
@@ -462,31 +480,31 @@ var METRICS_QUERY_MAX_GROUP_BY = 3;
462
480
  var METRICS_QUERY_MAX_FILTERS = 20;
463
481
  var METRICS_QUERY_MAX_METRICS = 10;
464
482
  var METRIC_ALIAS_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
465
- var metricAliasSchema = z14.string().min(1).max(64).regex(
483
+ var metricAliasSchema = z15.string().min(1).max(64).regex(
466
484
  METRIC_ALIAS_PATTERN,
467
485
  "Must start with a letter or underscore, and contain only letters, digits, and underscores \u2014 this becomes a SQL column alias."
468
486
  ).optional();
469
- var MetricsFilterValueSchema = z14.union([
470
- z14.string().max(255),
471
- z14.number(),
472
- z14.boolean(),
473
- z14.array(z14.union([z14.string().max(255), z14.number()])).min(1).max(50)
487
+ var MetricsFilterValueSchema = z15.union([
488
+ z15.string().max(255),
489
+ z15.number(),
490
+ z15.boolean(),
491
+ z15.array(z15.union([z15.string().max(255), z15.number()])).min(1).max(50)
474
492
  ]);
475
- var orderBySchema = z14.object({
476
- key: z14.string().min(1).max(64).regex(
493
+ var orderBySchema = z15.object({
494
+ key: z15.string().min(1).max(64).regex(
477
495
  METRIC_ALIAS_PATTERN,
478
496
  "Must start with a letter or underscore, and contain only letters, digits, and underscores \u2014 every valid output column name already looks like this."
479
497
  ).describe(
480
498
  "An output column name from this same query \u2014 either a `groupBy` field name, or a metric\u2019s `alias` (or its default name: `${aggregation}` for `count`, `${aggregation}_${field}` otherwise, e.g. `sum_amount`). Must match `^[a-zA-Z_][a-zA-Z0-9_]*$` \u2014 every real output column name already does, so this only ever rejects a value that could never have been one."
481
499
  ),
482
- direction: z14.enum(["asc", "desc"])
500
+ direction: z15.enum(["asc", "desc"])
483
501
  }).describe(
484
502
  "Sort the result rows by any output column \u2014 including the bucket field itself for a `date_bucket` query (e.g. `createdAt`). Omit to get ascending-by-bucket order for a date-bucketed query, or implementation-defined (not guaranteed stable) order otherwise."
485
503
  );
486
- var limitSchema = z14.number().int().min(1).max(METRICS_QUERY_MAX_ROW_LIMIT).default(METRICS_QUERY_DEFAULT_ROW_LIMIT).describe(
504
+ var limitSchema = z15.number().int().min(1).max(METRICS_QUERY_MAX_ROW_LIMIT).default(METRICS_QUERY_DEFAULT_ROW_LIMIT).describe(
487
505
  `Max rows to return, ${1}\u2013${METRICS_QUERY_MAX_ROW_LIMIT}, default ${METRICS_QUERY_DEFAULT_ROW_LIMIT}. If more rows matched, \`meta.truncated\` is \`true\` on the response \u2014 narrow the query instead of just raising this.`
488
506
  );
489
- var ChargesQueryFieldSchema = z14.enum([
507
+ var ChargesQueryFieldSchema = z15.enum([
490
508
  "status",
491
509
  "source",
492
510
  "apiKeyId",
@@ -497,124 +515,124 @@ var ChargesQueryFieldSchema = z14.enum([
497
515
  ]).describe(
498
516
  "A `Charge` field to filter or group by \u2014 see `ChargeStatusSchema` for `status`'s own possible values (charges.md). `source`/`externalRef` are free-form strings your own integration set at creation, not a fixed enum. `escrowReleaserAddress` is `null` for a normal charge \u2014 filter `escrowReleaserAddress` with operator `neq`/value `null` to isolate escrow-configured charges (see `escrow` in charges.md)."
499
517
  );
500
- var ChargesMetricFieldSchema = z14.enum(["amount", "amountReceived", "feePercent", "escrowFeePercent"]).describe(
518
+ var ChargesMetricFieldSchema = z15.enum(["amount", "amountReceived", "feePercent", "escrowFeePercent"]).describe(
501
519
  "A `Charge` numeric field to aggregate. `amount`/`amountReceived` are decimal currency amounts (requested vs. actually received \u2014 see `charges.md`). `feePercent` is the platform fee frozen on the charge at creation, e.g. `1.5` means 1.5%. `escrowFeePercent` is the additional escrow-specific fee component, only present on escrow-configured charges \u2014 see `docs/payments.md`."
502
520
  );
503
- var ChargesDateFieldSchema = z14.enum(["createdAt", "confirmedAt", "lastActivityAt", "expiresAt", "escrowReleasedAt"]).describe(
521
+ var ChargesDateFieldSchema = z15.enum(["createdAt", "confirmedAt", "lastActivityAt", "expiresAt", "escrowReleasedAt"]).describe(
504
522
  "A `Charge` timestamp to filter/bucket by. `confirmedAt` is `null` until the charge reaches `confirmed` \u2014 a `dateRange`/`date_bucket` on it implicitly excludes every charge that never confirmed. `expiresAt` is always present (set at creation), useful for e.g. finding charges expiring soon or measuring how close to expiry charges typically resolve. `escrowReleasedAt` is `null` until an escrow-configured charge is actually released \u2014 same implicit-exclusion behavior as `confirmedAt`, scoped to escrow charges only."
505
523
  );
506
- var ChargesFilterSchema = z14.object({
524
+ var ChargesFilterSchema = z15.object({
507
525
  field: ChargesQueryFieldSchema,
508
526
  operator: MetricsFilterOperatorSchema,
509
527
  value: MetricsFilterValueSchema
510
528
  });
511
- var ChargesGroupBySchema = z14.union([
512
- z14.object({ type: z14.literal("field"), field: ChargesQueryFieldSchema }),
513
- z14.object({
514
- type: z14.literal("date_bucket"),
529
+ var ChargesGroupBySchema = z15.union([
530
+ z15.object({ type: z15.literal("field"), field: ChargesQueryFieldSchema }),
531
+ z15.object({
532
+ type: z15.literal("date_bucket"),
515
533
  field: ChargesDateFieldSchema,
516
534
  granularity: MetricsDateGranularitySchema
517
535
  })
518
536
  ]);
519
- var ChargesMetricSchema = z14.object({
537
+ var ChargesMetricSchema = z15.object({
520
538
  aggregation: MetricsAggregationSchema,
521
539
  field: ChargesMetricFieldSchema.optional(),
522
540
  alias: metricAliasSchema
523
541
  });
524
- var ChargesMetricsQuerySchema = z14.object({
525
- resource: z14.literal("charges"),
542
+ var ChargesMetricsQuerySchema = z15.object({
543
+ resource: z15.literal("charges"),
526
544
  environment: metricsQueryEnvironmentSchema,
527
- dateRange: z14.object({
545
+ dateRange: z15.object({
528
546
  field: ChargesDateFieldSchema,
529
- from: z14.string().max(64).datetime(),
530
- to: z14.string().max(64).datetime()
547
+ from: z15.string().max(64).datetime(),
548
+ to: z15.string().max(64).datetime()
531
549
  }),
532
- groupBy: z14.array(ChargesGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
533
- metrics: z14.array(ChargesMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
534
- filters: z14.array(ChargesFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
550
+ groupBy: z15.array(ChargesGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
551
+ metrics: z15.array(ChargesMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
552
+ filters: z15.array(ChargesFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
535
553
  orderBy: orderBySchema.optional(),
536
554
  limit: limitSchema
537
555
  });
538
- var TransactionsQueryFieldSchema = z14.enum(["network", "token", "source", "causedTransition"]).describe(
556
+ var TransactionsQueryFieldSchema = z15.enum(["network", "token", "source", "causedTransition"]).describe(
539
557
  "A `Transaction` field to filter or group by \u2014 see `NetworkSchema`/`TokenSchema`/`TransactionSourceSchema` for their possible values. `causedTransition` is `true` only for the transfer(s) that actually flipped the charge's `status` \u2014 a charge paid in installments can have more than one; filtering/grouping on it excludes no-op duplicate transfers (see `TimelineEvent.causedTransition` in charges.md for the full explanation)."
540
558
  );
541
- var TransactionsMetricFieldSchema = z14.enum(["amount"]).describe("The transfer amount, in the charge's `currency` units.");
542
- var TransactionsDateFieldSchema = z14.enum(["detectedAt"]).describe("When Klappay detected this transfer on-chain (not when it was mined).");
543
- var TransactionsFilterSchema = z14.object({
559
+ var TransactionsMetricFieldSchema = z15.enum(["amount"]).describe("The transfer amount, in the charge's `currency` units.");
560
+ var TransactionsDateFieldSchema = z15.enum(["detectedAt"]).describe("When Klappay detected this transfer on-chain (not when it was mined).");
561
+ var TransactionsFilterSchema = z15.object({
544
562
  field: TransactionsQueryFieldSchema,
545
563
  operator: MetricsFilterOperatorSchema,
546
564
  value: MetricsFilterValueSchema
547
565
  });
548
- var TransactionsGroupBySchema = z14.union([
549
- z14.object({ type: z14.literal("field"), field: TransactionsQueryFieldSchema }),
550
- z14.object({
551
- type: z14.literal("date_bucket"),
566
+ var TransactionsGroupBySchema = z15.union([
567
+ z15.object({ type: z15.literal("field"), field: TransactionsQueryFieldSchema }),
568
+ z15.object({
569
+ type: z15.literal("date_bucket"),
552
570
  field: TransactionsDateFieldSchema,
553
571
  granularity: MetricsDateGranularitySchema
554
572
  })
555
573
  ]);
556
- var TransactionsMetricSchema = z14.object({
574
+ var TransactionsMetricSchema = z15.object({
557
575
  aggregation: MetricsAggregationSchema,
558
576
  field: TransactionsMetricFieldSchema.optional(),
559
577
  alias: metricAliasSchema
560
578
  });
561
- var TransactionsMetricsQuerySchema = z14.object({
562
- resource: z14.literal("transactions"),
579
+ var TransactionsMetricsQuerySchema = z15.object({
580
+ resource: z15.literal("transactions"),
563
581
  environment: metricsQueryEnvironmentSchema,
564
- dateRange: z14.object({
582
+ dateRange: z15.object({
565
583
  field: TransactionsDateFieldSchema,
566
- from: z14.string().max(64).datetime(),
567
- to: z14.string().max(64).datetime()
584
+ from: z15.string().max(64).datetime(),
585
+ to: z15.string().max(64).datetime()
568
586
  }),
569
- groupBy: z14.array(TransactionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
570
- metrics: z14.array(TransactionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
571
- filters: z14.array(TransactionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
587
+ groupBy: z15.array(TransactionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
588
+ metrics: z15.array(TransactionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
589
+ filters: z15.array(TransactionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
572
590
  orderBy: orderBySchema.optional(),
573
591
  limit: limitSchema
574
592
  });
575
- var DistributionsQueryFieldSchema = z14.enum(["status", "network", "token", "distributorAddress"]).describe(
593
+ var DistributionsQueryFieldSchema = z15.enum(["status", "network", "token", "distributorAddress"]).describe(
576
594
  "A `SplitDistribution` field to filter or group by \u2014 see `SplitDistributionStatusSchema`/`NetworkSchema`/`TokenSchema` for their possible values. `distributorAddress` is the public on-chain address that actually called `distribute()` for a `completed` distribution \u2014 Klappay's own operator address if settled by Klappay's own worker, a community keeper's address if settled externally (or `null` on the rare case that lookup failed), `null` for every non-`completed` status."
577
595
  );
578
- var DistributionsMetricFieldSchema = z14.enum(["attempts"]).describe(
596
+ var DistributionsMetricFieldSchema = z15.enum(["attempts"]).describe(
579
597
  "How many times a payout was attempted for this settlement so far \u2014 incremented on every attempt, whether it succeeded or is being retried after failing. A high `attempts` alongside `status: 'failed'` means every automatic retry was exhausted."
580
598
  );
581
- var DistributionsDateFieldSchema = z14.enum(["createdAt", "processingStartedAt", "completedAt"]).describe(
599
+ var DistributionsDateFieldSchema = z15.enum(["createdAt", "processingStartedAt", "completedAt"]).describe(
582
600
  "`createdAt`: when this settlement was queued. `processingStartedAt`: when a worker began its most recent attempt at the payout \u2014 `null` until the first attempt, then overwritten on every subsequent retry, so it reflects the *latest* attempt's start, not the first. `completedAt`: when it actually paid out \u2014 `null` until `status` reaches `completed`, so a `dateRange`/`date_bucket` on it implicitly excludes every distribution still pending/processing/failed."
583
601
  );
584
- var DistributionsFilterSchema = z14.object({
602
+ var DistributionsFilterSchema = z15.object({
585
603
  field: DistributionsQueryFieldSchema,
586
604
  operator: MetricsFilterOperatorSchema,
587
605
  value: MetricsFilterValueSchema
588
606
  });
589
- var DistributionsGroupBySchema = z14.union([
590
- z14.object({ type: z14.literal("field"), field: DistributionsQueryFieldSchema }),
591
- z14.object({
592
- type: z14.literal("date_bucket"),
607
+ var DistributionsGroupBySchema = z15.union([
608
+ z15.object({ type: z15.literal("field"), field: DistributionsQueryFieldSchema }),
609
+ z15.object({
610
+ type: z15.literal("date_bucket"),
593
611
  field: DistributionsDateFieldSchema,
594
612
  granularity: MetricsDateGranularitySchema
595
613
  })
596
614
  ]);
597
- var DistributionsMetricSchema = z14.object({
615
+ var DistributionsMetricSchema = z15.object({
598
616
  aggregation: MetricsAggregationSchema,
599
617
  field: DistributionsMetricFieldSchema.optional(),
600
618
  alias: metricAliasSchema
601
619
  });
602
- var DistributionsMetricsQuerySchema = z14.object({
603
- resource: z14.literal("distributions"),
620
+ var DistributionsMetricsQuerySchema = z15.object({
621
+ resource: z15.literal("distributions"),
604
622
  environment: metricsQueryEnvironmentSchema,
605
- dateRange: z14.object({
623
+ dateRange: z15.object({
606
624
  field: DistributionsDateFieldSchema,
607
- from: z14.string().max(64).datetime(),
608
- to: z14.string().max(64).datetime()
625
+ from: z15.string().max(64).datetime(),
626
+ to: z15.string().max(64).datetime()
609
627
  }),
610
- groupBy: z14.array(DistributionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
611
- metrics: z14.array(DistributionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
612
- filters: z14.array(DistributionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
628
+ groupBy: z15.array(DistributionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
629
+ metrics: z15.array(DistributionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
630
+ filters: z15.array(DistributionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
613
631
  orderBy: orderBySchema.optional(),
614
632
  limit: limitSchema
615
633
  });
616
634
  var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
617
- var MetricsQuerySchema = z14.discriminatedUnion("resource", [
635
+ var MetricsQuerySchema = z15.discriminatedUnion("resource", [
618
636
  ChargesMetricsQuerySchema,
619
637
  TransactionsMetricsQuerySchema,
620
638
  DistributionsMetricsQuerySchema
@@ -623,7 +641,7 @@ var MetricsQuerySchema = z14.discriminatedUnion("resource", [
623
641
  const to = new Date(input.dateRange.to);
624
642
  if (from >= to) {
625
643
  ctx.addIssue({
626
- code: z14.ZodIssueCode.custom,
644
+ code: z15.ZodIssueCode.custom,
627
645
  message: "`dateRange.from` must be before `dateRange.to`.",
628
646
  path: ["dateRange", "from"]
629
647
  });
@@ -631,7 +649,7 @@ var MetricsQuerySchema = z14.discriminatedUnion("resource", [
631
649
  const spanDays = (to.getTime() - from.getTime()) / ONE_DAY_MS;
632
650
  if (spanDays > MAX_METRICS_QUERY_DATE_RANGE_DAYS) {
633
651
  ctx.addIssue({
634
- code: z14.ZodIssueCode.custom,
652
+ code: z15.ZodIssueCode.custom,
635
653
  message: `\`dateRange\` cannot span more than ${MAX_METRICS_QUERY_DATE_RANGE_DAYS} days.`,
636
654
  path: ["dateRange", "to"]
637
655
  });
@@ -639,7 +657,7 @@ var MetricsQuerySchema = z14.discriminatedUnion("resource", [
639
657
  const dateBucketCount = input.groupBy.filter((entry) => entry.type === "date_bucket").length;
640
658
  if (dateBucketCount > 1) {
641
659
  ctx.addIssue({
642
- code: z14.ZodIssueCode.custom,
660
+ code: z15.ZodIssueCode.custom,
643
661
  message: "At most one `date_bucket` entry is allowed in `groupBy`.",
644
662
  path: ["groupBy"]
645
663
  });
@@ -647,7 +665,7 @@ var MetricsQuerySchema = z14.discriminatedUnion("resource", [
647
665
  input.metrics.forEach((metric, index) => {
648
666
  if (metric.aggregation !== "count" && metric.field === void 0) {
649
667
  ctx.addIssue({
650
- code: z14.ZodIssueCode.custom,
668
+ code: z15.ZodIssueCode.custom,
651
669
  message: "`field` is required unless `aggregation` is `count`.",
652
670
  path: ["metrics", index, "field"]
653
671
  });
@@ -656,7 +674,7 @@ var MetricsQuerySchema = z14.discriminatedUnion("resource", [
656
674
  const aliases = input.metrics.map((metric) => metric.alias).filter((alias) => alias !== void 0);
657
675
  if (new Set(aliases).size !== aliases.length) {
658
676
  ctx.addIssue({
659
- code: z14.ZodIssueCode.custom,
677
+ code: z15.ZodIssueCode.custom,
660
678
  message: "Every `metrics[].alias` must be unique.",
661
679
  path: ["metrics"]
662
680
  });
@@ -665,32 +683,32 @@ var MetricsQuerySchema = z14.discriminatedUnion("resource", [
665
683
  input.metrics.forEach((metric, index) => {
666
684
  if (metric.alias !== void 0 && reservedNames.has(metric.alias)) {
667
685
  ctx.addIssue({
668
- code: z14.ZodIssueCode.custom,
686
+ code: z15.ZodIssueCode.custom,
669
687
  message: `\`alias\` "${metric.alias}" collides with a \`groupBy\` field name (or the reserved word "bucket") \u2014 choose a different alias.`,
670
688
  path: ["metrics", index, "alias"]
671
689
  });
672
690
  }
673
691
  });
674
692
  });
675
- var MetricsQueryResultRowSchema = z14.record(
676
- z14.string(),
677
- z14.union([z14.string(), z14.number(), z14.boolean(), z14.null()])
693
+ var MetricsQueryResultRowSchema = z15.record(
694
+ z15.string(),
695
+ z15.union([z15.string(), z15.number(), z15.boolean(), z15.null()])
678
696
  );
679
- var MetricsQueryResultSchema = z14.object({
680
- data: z14.array(MetricsQueryResultRowSchema),
681
- meta: z14.object({
697
+ var MetricsQueryResultSchema = z15.object({
698
+ data: z15.array(MetricsQueryResultRowSchema),
699
+ meta: z15.object({
682
700
  resource: MetricsResourceSchema,
683
701
  environment: EnvironmentSchema,
684
- rowCount: z14.number().int().describe("Number of rows in `data`."),
685
- truncated: z14.boolean().describe(
702
+ rowCount: z15.number().int().describe("Number of rows in `data`."),
703
+ truncated: z15.boolean().describe(
686
704
  "`true` if more rows matched than `limit` allowed \u2014 `data` holds only the first `limit`."
687
705
  )
688
706
  })
689
707
  });
690
708
 
691
709
  // src/webhook-events.ts
692
- import { z as z15 } from "zod";
693
- var ChargeWebhookEventTypeSchema = z15.enum([
710
+ import { z as z16 } from "zod";
711
+ var ChargeWebhookEventTypeSchema = z16.enum([
694
712
  "charge.created",
695
713
  "charge.partially_paid",
696
714
  "charge.confirmed",
@@ -704,14 +722,14 @@ var ChargeWebhookEventTypeSchema = z15.enum([
704
722
  ]).describe(
705
723
  'Note the distinction between `charge.confirmed` and `charge.settled`: `confirmed` means the payment was detected on-chain; `settled` means the merchant\'s wallet actually received the funds \u2014 a separate, later step. Subscribe to `confirmed` if you only need "will I get paid," or `settled` if you need "has the money actually arrived." `charge.overpaid` fires alongside `charge.confirmed`/`charge.partially_paid` whenever the cumulative amount received ends up above `amount` (see `Charge.isOverpaid`). `charge.escrow_released` fires once an escrow-configured charge\'s funds have been moved out of its Safe to the split address by `POST /v1/charges/{id}/release` \u2014 a normal `charge.settled` still follows once the split itself finishes distributing. `charge.escrow_refunded` fires once an escrow-configured charge\'s funds have been moved out of its Safe back to the payer by `POST /v1/charges/{id}/refund` \u2014 mutually exclusive with `charge.escrow_released`, an escrow charge only ever emits one of the two. Every event in this category carries the full `Charge` object as `data`.'
706
724
  );
707
- var WebhookDeliveryEventTypeSchema = z15.enum(["webhook.delivery_failed", "webhook.delivery_recovered", "webhook.endpoint_unhealthy"]).describe(
725
+ var WebhookDeliveryEventTypeSchema = z16.enum(["webhook.delivery_failed", "webhook.delivery_recovered", "webhook.endpoint_unhealthy"]).describe(
708
726
  "Meta-events about the health of your own webhook endpoints \u2014 useful for monitoring without polling `GET /v1/webhooks/{id}/deliveries`. `webhook.endpoint_unhealthy` fires once when a webhook's failure rate over the trailing 24h crosses 20%, and `webhook.delivery_recovered` fires once when a delivery to that webhook next succeeds. `data` for every event in this category: `{ webhookId, url, failureRatio? }` (`failureRatio` only present on `webhook.endpoint_unhealthy`)."
709
727
  );
710
- var WebhookEventTypeSchema = z15.union([
728
+ var WebhookEventTypeSchema = z16.union([
711
729
  ChargeWebhookEventTypeSchema,
712
730
  WebhookDeliveryEventTypeSchema
713
731
  ]);
714
- var WebhookCategorySchema = z15.enum(["payments", "webhooks"]).describe(
732
+ var WebhookCategorySchema = z16.enum(["payments", "webhooks"]).describe(
715
733
  "Subscribe to every event in a category via `eventCategories` instead of listing events one by one \u2014 new events added to a category later arrive automatically, no subscription update needed."
716
734
  );
717
735
  function buildCategoryMap() {
@@ -741,101 +759,101 @@ var TriggerableChargeEventSchema = ChargeWebhookEventTypeSchema.exclude([
741
759
  );
742
760
 
743
761
  // src/webhooks.ts
744
- import { z as z16 } from "zod";
762
+ import { z as z17 } from "zod";
745
763
  var WEBHOOK_EVENTS_WILDCARD = "*";
746
- var CreateWebhookSchema = z16.object({
747
- url: z16.string().max(2048).url().describe(
764
+ var CreateWebhookSchema = z17.object({
765
+ url: z17.string().max(2048).url().describe(
748
766
  "Must be HTTPS and resolve to a public address \u2014 private/internal IPs are rejected."
749
767
  ),
750
- events: z16.array(z16.union([WebhookEventTypeSchema, z16.literal(WEBHOOK_EVENTS_WILDCARD)])).max(Object.keys(EVENT_CATEGORY_MAP).length + 1).default([]).describe(
768
+ events: z17.array(z17.union([WebhookEventTypeSchema, z17.literal(WEBHOOK_EVENTS_WILDCARD)])).max(Object.keys(EVENT_CATEGORY_MAP).length + 1).default([]).describe(
751
769
  'Individual event types to receive, or `"*"` for every event (combine with `excludeEvents` to opt back out of specific ones). Omit in favor of `eventCategories` if you want whole categories instead.'
752
770
  ),
753
- eventCategories: z16.array(WebhookCategorySchema).max(WebhookCategorySchema.options.length).default([]).describe(
771
+ eventCategories: z17.array(WebhookCategorySchema).max(WebhookCategorySchema.options.length).default([]).describe(
754
772
  "Subscribe to every event in these categories. At least one of `events` or `eventCategories` is required."
755
773
  ),
756
- excludeEvents: z16.array(WebhookEventTypeSchema).max(Object.keys(EVENT_CATEGORY_MAP).length).default([]).describe(
774
+ excludeEvents: z17.array(WebhookEventTypeSchema).max(Object.keys(EVENT_CATEGORY_MAP).length).default([]).describe(
757
775
  'Event types to exclude even if selected via `events: ["*"]` or `eventCategories`.'
758
776
  )
759
777
  }).refine((v) => v.events.length > 0 || v.eventCategories.length > 0, {
760
778
  message: "must select at least one event via `events` or `eventCategories`",
761
779
  path: ["events"]
762
780
  });
763
- var WebhookSchema = z16.object({
764
- id: z16.string(),
781
+ var WebhookSchema = z17.object({
782
+ id: z17.string(),
765
783
  environment: EnvironmentSchema.nullable().describe(
766
784
  "Which environment's API key created this webhook \u2014 `live` or `test`. Every event is only ever delivered to a webhook whose `environment` matches the event's own (or to a webhook with `environment: null`, which receives every environment \u2014 the case for every webhook created before this field existed)."
767
785
  ),
768
- url: z16.string(),
769
- events: z16.array(WebhookEventTypeSchema),
770
- eventCategories: z16.array(WebhookCategorySchema),
771
- excludeEvents: z16.array(WebhookEventTypeSchema),
772
- isWildcard: z16.boolean(),
773
- secret: z16.string().describe(
786
+ url: z17.string(),
787
+ events: z17.array(WebhookEventTypeSchema),
788
+ eventCategories: z17.array(WebhookCategorySchema),
789
+ excludeEvents: z17.array(WebhookEventTypeSchema),
790
+ isWildcard: z17.boolean(),
791
+ secret: z17.string().describe(
774
792
  "The signing secret, used to verify the `X-Klappay-Signature` header on every delivery. Returned in full only this once \u2014 store it now, it is not recoverable afterward. Header format: `t=<unix-seconds>,v1=<hex-encoded HMAC-SHA256>`. Compute the expected signature as `HMAC-SHA256(secret, \"${t}.${raw request body}\")` (hex-encoded) and compare it to `v1` using a constant-time comparison; as a replay-protection measure, also reject if `t` is too far from the current time \u2014 Klappay does not enforce or check any particular tolerance server-side, so the exact threshold is entirely the receiver's own policy call. An official SDK's `constructEvent()`/`verifySignature()` do this for you, defaulting to a 300-second tolerance, overridable via `constructEvent`'s `toleranceSeconds` option \u2014 see github.com/klappay for available SDKs."
775
793
  ),
776
- createdAt: z16.string().datetime()
794
+ createdAt: z17.string().datetime()
777
795
  });
778
796
  var WebhookListItemSchema = WebhookSchema.omit({ secret: true }).extend({
779
- hint: z16.string().describe("A truncated, safe-to-display form of the secret (e.g. `whsec_...ab12`).")
797
+ hint: z17.string().describe("A truncated, safe-to-display form of the secret (e.g. `whsec_...ab12`).")
780
798
  });
781
- var WebhookPayloadSchema = z16.object({
782
- id: z16.string().describe(
799
+ var WebhookPayloadSchema = z17.object({
800
+ id: z17.string().describe(
783
801
  "Unique id for this specific delivery \u2014 also sent as the `X-Klappay-Delivery` header."
784
802
  ),
785
803
  event: WebhookEventTypeSchema,
786
- createdAt: z16.string().datetime(),
787
- data: z16.unknown().describe(
804
+ createdAt: z17.string().datetime(),
805
+ data: z17.unknown().describe(
788
806
  "Event-specific data. Charge events (`charge.*`) carry the full `Charge` object; webhook-delivery events carry a smaller, event-specific object \u2014 see `WebhookEventDataMap`/`TypedWebhookPayload` for the exact shape per event, or docs/webhooks.md."
789
807
  )
790
808
  });
791
- var WebhookDeliveryStatusSchema = z16.enum(["pending", "delivered", "failed"]);
792
- var WebhookDeliverySchema = z16.object({
793
- id: z16.string(),
794
- webhookId: z16.string(),
809
+ var WebhookDeliveryStatusSchema = z17.enum(["pending", "delivered", "failed"]);
810
+ var WebhookDeliverySchema = z17.object({
811
+ id: z17.string(),
812
+ webhookId: z17.string(),
795
813
  event: WebhookEventTypeSchema,
796
814
  status: WebhookDeliveryStatusSchema.describe(
797
815
  "`pending`: still retrying. `delivered`: got a 2xx response. `failed`: retries exhausted (5 attempts over ~24h) \u2014 use `POST /v1/webhooks/{id}/deliveries/{deliveryId}/retry` to try again manually."
798
816
  ),
799
- attempts: z16.number(),
800
- responseCode: z16.number().nullable().describe(
817
+ attempts: z17.number(),
818
+ responseCode: z17.number().nullable().describe(
801
819
  "HTTP status your endpoint returned on the most recent attempt. `null` if every attempt failed to connect at all."
802
820
  ),
803
- nextRetryAt: z16.string().datetime().nullable(),
804
- deliveredAt: z16.string().datetime().nullable(),
805
- createdAt: z16.string().datetime()
821
+ nextRetryAt: z17.string().datetime().nullable(),
822
+ deliveredAt: z17.string().datetime().nullable(),
823
+ createdAt: z17.string().datetime()
806
824
  });
807
825
  var ListWebhookDeliveriesSchema = PaginationQuerySchema;
808
826
  var PaginatedWebhookDeliveriesSchema = paginatedSchema(WebhookDeliverySchema);
809
827
 
810
828
  // src/recipients.ts
811
- import { z as z17 } from "zod";
829
+ import { z as z18 } from "zod";
812
830
  var EVM_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/;
813
- var CreateRecipientSchema = z17.object({
814
- address: z17.string().regex(EVM_ADDRESS_REGEX, "must be a 20-byte hex address").describe("EVM address to register as a trusted split recipient for your organization."),
815
- label: z17.string().min(1).max(64).optional().describe('Free-form label for your own bookkeeping (e.g. `"supplier"`) \u2014 never interpreted.')
831
+ var CreateRecipientSchema = z18.object({
832
+ address: z18.string().regex(EVM_ADDRESS_REGEX, "must be a 20-byte hex address").describe("EVM address to register as a trusted split recipient for your organization."),
833
+ label: z18.string().min(1).max(64).optional().describe('Free-form label for your own bookkeeping (e.g. `"supplier"`) \u2014 never interpreted.')
816
834
  });
817
- var RecipientSchema = z17.object({
818
- id: z17.string().describe(
835
+ var RecipientSchema = z18.object({
836
+ id: z18.string().describe(
819
837
  "Klappay-generated id, e.g. `rc_...` \u2014 this, not the raw address, is what a charge's `splitRecipients[].recipientId` references."
820
838
  ),
821
839
  environment: EnvironmentSchema,
822
- address: z17.string(),
823
- label: z17.string().nullable(),
824
- payout: z17.boolean().describe(
840
+ address: z18.string(),
841
+ label: z18.string().nullable(),
842
+ payout: z18.boolean().describe(
825
843
  "Whether this recipient is eligible to be used as an API key's `payoutAddress` (in addition to being referenceable in a split, which every non-revoked recipient already is). Set via `PATCH /v1/recipients/{id}` \u2014 requires the `recipients:manage_payout` scope, deliberately separate from `recipients:write`."
826
844
  ),
827
- createdAt: z17.string().datetime()
845
+ createdAt: z18.string().datetime()
828
846
  });
829
- var SetRecipientPayoutSchema = z17.object({
830
- payout: z17.boolean().describe("New payout-eligibility value for this recipient.")
847
+ var SetRecipientPayoutSchema = z18.object({
848
+ payout: z18.boolean().describe("New payout-eligibility value for this recipient.")
831
849
  });
832
850
 
833
851
  // src/timeline.ts
834
- import { z as z18 } from "zod";
835
- var TransactionSourceSchema = z18.enum(["moralis_webhook", "reconciliation_job", "sandbox"]).describe(
836
- "How this transfer was detected: `moralis_webhook` (the normal path), `reconciliation_job` (a fallback poller caught it after the webhook was missed or delayed), or `sandbox` (simulated via `POST /v1/sandbox/charges/{id}/trigger`, no real on-chain transfer)."
852
+ import { z as z19 } from "zod";
853
+ var TransactionSourceSchema = z19.enum(["contract_watcher", "reconciliation_job", "sandbox"]).describe(
854
+ "How this transfer was detected: `contract_watcher` (the normal path \u2014 a real-time on-chain event subscription), `reconciliation_job` (a fallback poller caught it after the watcher missed or delayed it), or `sandbox` (simulated via `POST /v1/sandbox/charges/{id}/trigger`, no real on-chain transfer)."
837
855
  );
838
- var TimelineEventTypeSchema = z18.enum([
856
+ var TimelineEventTypeSchema = z19.enum([
839
857
  "charge.created",
840
858
  "charge.expired",
841
859
  "transaction.detected",
@@ -847,13 +865,13 @@ var TimelineEventTypeSchema = z18.enum([
847
865
  ]).describe(
848
866
  "`charge.created`: the charge was created. `charge.expired`: `expiresAt` passed with no full payment. `transaction.detected`: a raw on-chain transfer was seen (see the `event`-shaped fields below for details \u2014 a charge can have more than one, e.g. a partial payment followed by the rest). `split.distributed`: a payout to the merchant completed on-chain, for one contributing `(token, network)` pair \u2014 a charge settled across more than one pair emits one of these per pair (see the `token`/`network` fields below). `webhook.dispatched`/`webhook.delivered`/`webhook.failed`: one specific delivery *attempt* for one webhook subscription \u2014 `failed` here means this single attempt failed, not that all retries were exhausted (see `WebhookDeliveryStatusSchema` for the exhausted-all-retries state). `transfer.reclaimed`: an on-chain transfer was detected but never reached its network's required confirmation depth before vanishing (reverted, or dropped from the canonical chain) \u2014 see `txHash` below for which transfer."
849
867
  );
850
- var TimelineEventSchema = z18.object({
868
+ var TimelineEventSchema = z19.object({
851
869
  type: TimelineEventTypeSchema,
852
- at: z18.string().datetime(),
853
- txHash: z18.string().optional().describe(
870
+ at: z19.string().datetime(),
871
+ txHash: z19.string().optional().describe(
854
872
  "Present for `transaction.detected`, `split.distributed`, and `transfer.reclaimed` events only."
855
873
  ),
856
- amount: z18.number().optional().describe(
874
+ amount: z19.number().optional().describe(
857
875
  "Present for `transaction.detected` events only \u2014 the amount that specific transfer carried."
858
876
  ),
859
877
  source: TransactionSourceSchema.optional().describe(
@@ -865,102 +883,114 @@ var TimelineEventSchema = z18.object({
865
883
  network: NetworkSchema.optional().describe(
866
884
  "Present for `transaction.detected` and `split.distributed` events \u2014 which network this specific transfer, or settlement, used."
867
885
  ),
868
- causedTransition: z18.boolean().optional().describe(
886
+ causedTransition: z19.boolean().optional().describe(
869
887
  "Present for `transaction.detected` events only. `true` if this specific transfer changed the charge's status (e.g. PENDING\u2192CONFIRMED) \u2014 a charge paid in installments can have more than one such event."
870
888
  ),
871
889
  event: WebhookEventTypeSchema.optional().describe(
872
890
  "Present for `webhook.*` events only \u2014 which event type this delivery was for."
873
891
  ),
874
- responseCode: z18.number().nullable().optional().describe(
892
+ responseCode: z19.number().nullable().optional().describe(
875
893
  "Present for `webhook.*` events only \u2014 HTTP status your endpoint returned, or `null` if the request never connected."
876
894
  ),
877
- attempts: z18.number().optional().describe(
895
+ attempts: z19.number().optional().describe(
878
896
  "Present for `webhook.*` events only \u2014 how many delivery attempts have been made so far."
879
897
  )
880
898
  });
881
899
 
882
900
  // src/health.ts
883
- import { z as z19 } from "zod";
884
- var HealthSchema = z19.object({
885
- status: z19.enum(["ok", "error"]).describe(
901
+ import { z as z20 } from "zod";
902
+ var HealthSchema = z20.object({
903
+ status: z20.enum(["ok", "error"]).describe(
886
904
  "`error` when the database connectivity check fails \u2014 the HTTP status code mirrors this (503 instead of 200), so a plain uptime check (not just a JSON-aware one) still catches a DB outage."
887
905
  ),
888
- version: z19.string(),
889
- timestamp: z19.string().datetime(),
890
- db: z19.enum(["ok", "error"]).describe("Result of a real database connectivity check, not just a process-alive check."),
891
- pendingWebhooks: z19.number().describe("Count of webhook deliveries still awaiting a successful attempt."),
892
- oldestPendingChargeAgeSeconds: z19.number().nullable().describe("Age of the oldest still-unpaid charge, in seconds. `null` if there are none."),
893
- lastMoralisEventAgeSeconds: z19.number().nullable().describe(
906
+ version: z20.string(),
907
+ timestamp: z20.string().datetime(),
908
+ db: z20.enum(["ok", "error"]).describe("Result of a real database connectivity check, not just a process-alive check."),
909
+ pendingWebhooks: z20.number().describe("Count of webhook deliveries still awaiting a successful attempt."),
910
+ oldestPendingChargeAgeSeconds: z20.number().nullable().describe("Age of the oldest still-unpaid charge, in seconds. `null` if there are none."),
911
+ lastContractWatcherEventAgeSeconds: z20.number().nullable().describe(
894
912
  "Seconds since the last on-chain payment notification was received \u2014 a cheap signal for whether payment detection is currently working. `null` if none have ever been received."
895
913
  )
896
914
  });
897
915
 
898
916
  // src/sandbox.ts
899
- import { z as z20 } from "zod";
900
- var SandboxTriggerSchema = z20.object({
917
+ import { z as z21 } from "zod";
918
+ var SandboxTriggerSchema = z21.object({
901
919
  event: TriggerableChargeEventSchema,
902
- amount: z20.number().positive().max(CHARGE_AMOUNT_MAX).optional().describe(
920
+ amount: z21.number().positive().max(CHARGE_AMOUNT_MAX).optional().describe(
903
921
  "Used with `charge.partially_paid` (amount to simulate as received so far \u2014 must be less than the charge amount, defaults to half of it if omitted) and with `charge.overpaid` (amount received \u2014 must be greater than the charge amount, defaults to 1.5x it if omitted). Ignored for every other event."
904
922
  )
905
923
  });
906
924
 
907
925
  // src/capabilities.ts
908
- import { z as z21 } from "zod";
909
- var CapabilitiesSchema = z21.object({
910
- acceptedPayments: z21.array(AcceptedPaymentSchema).describe(
911
- "Every `(token, network)` pair actually configured for your environment right now \u2014 read straight from the same lookup `POST /v1/charges` validates `acceptedPayments` against, so it can never list a pair that charge creation would then reject. Use this to build a picker UI instead of hardcoding the matrix client-side."
926
+ import { z as z22 } from "zod";
927
+ var CapabilitiesSchema = z22.object({
928
+ acceptedPayments: z22.array(AcceptedPaymentSchema).describe(
929
+ "Every `(token, network)` pair enabled for your environment right now, using the same deployment metadata and availability policy as `POST /v1/charges`. Cataloged but disabled pairs are omitted. Availability can change between requests, so handle `422 token_not_supported` when creating a charge. Use this to build a picker UI instead of hardcoding the matrix client-side."
912
930
  )
913
931
  });
914
932
 
915
933
  // src/swap.ts
916
- import { z as z22 } from "zod";
917
- var CreateSwapQuoteSchema = z22.object({
934
+ import { z as z23 } from "zod";
935
+ var CreateSwapQuoteSchema = z23.object({
918
936
  inputToken: AltTokenSchema.describe(
919
937
  "Which alt-cryptocurrency the payer wants to send \u2014 must be one of this charge's `swapAlternatives`, or `422 token_not_supported`."
920
938
  ),
921
939
  inputNetwork: NetworkSchema.describe(
922
- "Which network the payer will send `inputToken` on. Also picks which of this charge's `acceptedPayments` pairs the swap resolves to \u2014 a charge accepting USDC on both Base and Optimism resolves to whichever `inputNetwork` you pass. If the charge accepts more than one token on that same network, Klappay breaks the tie using its own trust ranking for that network (e.g. USDT over USDC on BNB Chain, where \"USDC\" is a third-party Binance-Peg token, not Circle's) \u2014 never a token the charge doesn't actually accept."
940
+ "Which network the payer will send `inputToken` on. Also picks which of this charge's `acceptedPayments` pairs the swap resolves to \u2014 a charge accepting USDC on both Base and Optimism resolves to whichever `inputNetwork` you pass. If the charge accepts more than one token on that same network, Klappay applies its token preference among enabled pairs the charge accepts. BNB Chain payments are currently disabled for both cataloged Binance-Peg tokens."
923
941
  ),
924
- takerAddress: z22.string().regex(/^0x[0-9a-fA-F]{40}$/, "must be a 20-byte hex address").describe(
942
+ takerAddress: z23.string().regex(/^0x[0-9a-fA-F]{40}$/, "must be a 20-byte hex address").describe(
925
943
  "The payer's own wallet address \u2014 the account that will sign and submit the swap transaction. Not validated against anything else; any well-formed address is accepted, since Klappay never custodies these funds."
926
944
  )
927
945
  });
928
- var SwapQuoteSchema = z22.object({
946
+ var SwapQuoteSchema = z23.object({
929
947
  inputToken: AltTokenSchema,
930
948
  inputNetwork: NetworkSchema,
931
- inputAmount: z22.number().describe(
949
+ inputAmount: z23.number().describe(
932
950
  "The ceiling of `inputToken` the payer needs available to sign for, in whole units (not wei/base units) \u2014 not necessarily the exact final cost. Any `inputToken` beyond what the swap actually needs (price moved favorably, less slippage than budgeted) is swapped back and refunded to the payer automatically, in the same transaction \u2014 never a separate step or a Klappay-side refund."
933
951
  ),
952
+ inputAmountExact: ExactAmountSchema.optional().describe(
953
+ "Exact ceiling of `inputToken` the payer needs available, in whole token units as a nonnegative decimal string with at most 18 fractional digits and no scientific notation. Prefer this over the legacy numeric `inputAmount`. Optional for compatibility with older API responses."
954
+ ),
934
955
  outputToken: TokenSchema.describe(
935
956
  "Which of this charge's `acceptedPayments` tokens the swap resolves to."
936
957
  ),
937
958
  outputNetwork: NetworkSchema,
938
- outputAmount: z22.number().describe(
939
- "The exact remaining amount owed on this charge (`amount - amountReceived`), in `currency` units \u2014 always what the merchant's split address receives, regardless of `inputAmount`."
959
+ outputAmount: z23.number().describe(
960
+ "The stablecoin amount requested by this quote, in whole `outputToken` units. Covers the remaining balance, rounded up only if the selected token cannot represent it exactly. This legacy JSON number can lose precision; use `outputAmountExact` for arithmetic. The actual transfer is verified on-chain before crediting the charge."
961
+ ),
962
+ outputAmountExact: ExactAmountSchema.optional().describe(
963
+ "Exact stablecoin amount requested by this quote, in whole `outputToken` units as a nonnegative decimal string with no scientific notation. Covers the remaining charge balance and rounds upward only to the smallest representable token unit when needed. Optional for compatibility with older API responses."
940
964
  ),
941
- fees: z22.object({
942
- klappayFee: z22.number().describe(
943
- "Klappay's own swap fee (1% today), in `outputToken` units \u2014 paid by the payer, on top of `inputAmount`, separate from the merchant's own `feePercent`. Never subtracted from `outputAmount`."
965
+ fees: z23.object({
966
+ klappayFee: z23.number().describe(
967
+ "Klappay's own swap fee (1% today), in `outputToken` units \u2014 paid by the payer and already reflected in `inputAmount`, separate from the merchant's own `feePercent`. Never subtracted from `outputAmount`."
968
+ ),
969
+ klappayFeeExact: ExactAmountSchema.optional().describe(
970
+ "Exact Klappay swap fee in whole `outputToken` units as a nonnegative decimal string with at most 18 fractional digits and no scientific notation. Already reflected in the input ceiling. Optional for compatibility with older API responses."
971
+ ),
972
+ zeroExFee: z23.number().nullable().describe(
973
+ "0x's own protocol fee for this specific token pair, in `outputToken` units, or `null` when this pair isn't currently one 0x charges on. Paid by the payer and already reflected in `inputAmount`, never subtracted from `outputAmount` \u2014 Klappay never sees this fee, it goes straight to 0x."
944
974
  ),
945
- zeroExFee: z22.number().nullable().describe(
946
- "0x's own protocol fee for this specific token pair, in `outputToken` units, or `null` when this pair isn't currently one 0x charges on. Also paid by the payer on top of `inputAmount`, also never subtracted from `outputAmount` \u2014 Klappay never sees this fee, it goes straight to 0x."
975
+ zeroExFeeExact: ExactAmountSchema.nullable().optional().describe(
976
+ "Exact 0x fee in whole `outputToken` units as a nonnegative decimal string with at most 18 fractional digits and no scientific notation, or `null` when no fee applies. Already reflected in the input ceiling. Optional for compatibility with older API responses."
947
977
  )
948
978
  }).describe(
949
979
  "Every fee the payer is charged for using swap-to-pay, broken out by who collects it \u2014 both already reflected in `inputAmount`, shown here separately for transparency. Neither ever reduces `outputAmount`."
950
980
  ),
951
- expiresAt: z22.string().datetime().describe(
981
+ expiresAt: z23.string().datetime().describe(
952
982
  "When this quote's price is no longer safely valid \u2014 a rough guide for the payer's UI countdown only. The actual price guarantee is enforced on-chain by the swap transaction itself (a signed Permit2 deadline, or a minimum-output check for a native-currency sell), not by this timestamp \u2014 submitting after it expires either reverts on-chain or simply gets re-quoted at the current price, never silently executes at a stale rate."
953
983
  ),
954
- transaction: z22.object({
955
- to: z22.string().describe("Contract address the payer's wallet must send this transaction to."),
956
- data: z22.string().describe("Calldata \u2014 opaque, must be sent unmodified."),
957
- value: z22.string().describe(
984
+ transaction: z23.object({
985
+ to: z23.string().describe("Contract address the payer's wallet must send this transaction to."),
986
+ data: z23.string().describe("Calldata \u2014 opaque, must be sent unmodified."),
987
+ value: z23.string().describe(
958
988
  "Native currency (ETH/BNB/MATIC/AVAX) to attach, in wei \u2014 `\"0\"` when `inputToken` isn't this network's native currency."
959
989
  )
960
990
  }).describe(
961
991
  "Pass this directly to the payer's wallet (e.g. viem/ethers `sendTransaction`) \u2014 Klappay never touches the payer's private key or submits anything on their behalf. If `permit2` is present on this response, sign that first and append the signature to this `data` before sending; if `permit2` is absent, send `transaction` as-is with no extra step."
962
992
  ),
963
- permit2: z22.object({ eip712: z22.record(z22.unknown()) }).nullish().describe(
993
+ permit2: z23.object({ eip712: z23.record(z23.unknown()) }).nullish().describe(
964
994
  "Present only when `inputToken` is an ERC-20 (today, only `BTC`) \u2014 the payer's wallet must sign this EIP-712 message and append the signature to `transaction.data` before sending, since an ERC-20 sell needs a Permit2 allowance signature that a native-currency sell doesn't. `null` (never omitted, in a genuine 0x-backed quote) when `inputToken` is a network's own native currency (ETH/BNB/MATIC/AVAX) \u2014 `transaction` is then ready to sign and send directly, no extra step."
965
995
  )
966
996
  });
@@ -1050,6 +1080,7 @@ export {
1050
1080
  SwapQuoteSchema,
1051
1081
  TOKEN_ADDRESSES,
1052
1082
  TOKEN_DECIMALS,
1083
+ TOKEN_DEPLOYMENTS,
1053
1084
  TimelineEventSchema,
1054
1085
  TimelineEventTypeSchema,
1055
1086
  TokenSchema,
@@ -1069,6 +1100,8 @@ export {
1069
1100
  WebhookPayloadSchema,
1070
1101
  WebhookSchema,
1071
1102
  findConflictingScopes,
1103
+ getTokenDeployment,
1104
+ isPaymentDeploymentEnabled,
1072
1105
  listSwapAlternatives,
1073
1106
  paginatedSchema
1074
1107
  };