@klappay/types 3.0.0 → 3.0.2

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
@@ -148,51 +148,88 @@ var TOKEN_ADDRESSES = {
148
148
  }
149
149
  };
150
150
 
151
+ // src/alt-tokens.ts
152
+ import { z as z7 } from "zod";
153
+ var AltTokenSchema = z7.enum(["ETH", "BNB", "MATIC", "AVAX", "BTC"]).describe(
154
+ "A non-stablecoin cryptocurrency Klappay trusts as swap input for a charge, via the 0x Swap API \u2014 swapped to one of the charge's `acceptedPayments` tokens before it ever reaches the merchant, so the merchant always receives USDC/USDT regardless of what the payer sent. Only a network's own native currency, plus `BTC` (wrapped) on the networks with deep, reputably-custodied liquidity, is trusted today (see `ALT_TOKEN_ADDRESSES`) \u2014 never assume every value here is available on every network."
155
+ );
156
+ var ALT_TOKEN_DECIMALS = {
157
+ ETH: 18,
158
+ BNB: 18,
159
+ MATIC: 18,
160
+ AVAX: 18,
161
+ BTC: 8
162
+ };
163
+ var ALT_TOKEN_ADDRESSES = {
164
+ base: { ETH: "native", BTC: "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf" },
165
+ optimism: { ETH: "native", BTC: "0x68f180fcCe6836688e9084f035309E29Bf0A2095" },
166
+ ethereum: { ETH: "native", BTC: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599" },
167
+ arbitrum: { ETH: "native", BTC: "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f" },
168
+ polygon: { MATIC: "native", BTC: "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6" },
169
+ avalanche: { AVAX: "native" },
170
+ bnb: { BNB: "native" }
171
+ };
172
+ var SwapAlternativeSchema = z7.object({
173
+ token: AltTokenSchema,
174
+ network: NetworkSchema.describe(
175
+ "Which network to send `token` on \u2014 pass both as `inputToken`/`inputNetwork` to `POST /v1/charges/{id}/quote`. The same token can appear more than once here, once per network that trusts it and that this charge accepts payment on."
176
+ )
177
+ });
178
+ function listSwapAlternatives(networks) {
179
+ const alternatives = [];
180
+ for (const network of new Set(networks)) {
181
+ for (const token of Object.keys(ALT_TOKEN_ADDRESSES[network] ?? {})) {
182
+ alternatives.push({ token, network });
183
+ }
184
+ }
185
+ return alternatives;
186
+ }
187
+
151
188
  // src/charges.ts
152
- import { z as z8 } from "zod";
189
+ import { z as z9 } from "zod";
153
190
 
154
191
  // src/checkout-metadata.ts
155
- import { z as z7 } from "zod";
192
+ import { z as z8 } from "zod";
156
193
  var CHECKOUT_PRODUCTS_MAX = 20;
157
- var CheckoutProductSchema = z7.object({
158
- name: z7.string().min(1).max(200).describe("What the payer is buying, shown as-is on the hosted checkout page."),
159
- quantity: z7.number().int().positive().max(9999).optional().describe("How many of this item. Omit for a single, unquantified item."),
160
- imageUrl: z7.string().url().max(2048).refine((value) => /^https?:\/\//.test(value), "must use http or https").optional().describe(
194
+ var CheckoutProductSchema = z8.object({
195
+ name: z8.string().min(1).max(200).describe("What the payer is buying, shown as-is on the hosted checkout page."),
196
+ quantity: z8.number().int().positive().max(9999).optional().describe("How many of this item. Omit for a single, unquantified item."),
197
+ imageUrl: z8.string().url().max(2048).refine((value) => /^https?:\/\//.test(value), "must use http or https").optional().describe(
161
198
  "Product image, fetched only by the payer's own browser \u2014 Klappay never fetches it server-side. Must be `http(s)`."
162
199
  )
163
200
  });
164
- var KlappayCheckoutMetadataSchema = z7.object({
165
- products: z7.array(CheckoutProductSchema).max(CHECKOUT_PRODUCTS_MAX).optional().describe(
201
+ var KlappayCheckoutMetadataSchema = z8.object({
202
+ products: z8.array(CheckoutProductSchema).max(CHECKOUT_PRODUCTS_MAX).optional().describe(
166
203
  `What the payer is buying, shown on the hosted checkout page \u2014 up to ${CHECKOUT_PRODUCTS_MAX} items. Purely informational: never validated against \`amount\`, never used by any payment or distribution logic.`
167
204
  )
168
205
  }).describe(
169
206
  "Reserved for Klappay \u2014 the one namespace inside `metadata` whose format is defined and enforced by Klappay, not by you. A `metadata.klappay` that does not match this shape is rejected outright (`400 validation_error`), unlike every other key in `metadata`, which accepts absolutely anything and never fails validation."
170
207
  );
171
- var MetadataWithKlappaySchema = z7.object({ klappay: KlappayCheckoutMetadataSchema.optional() }).catchall(z7.unknown()).describe(
208
+ var MetadataWithKlappaySchema = z8.object({ klappay: KlappayCheckoutMetadataSchema.optional() }).catchall(z8.unknown()).describe(
172
209
  "Arbitrary key/value data, returned as-is on every read. Put whatever you want in here \u2014 none of it is validated, except the `klappay` key, which is reserved for Klappay: if present, it must match `KlappayCheckoutMetadataSchema` exactly, or the whole request is rejected with `400 validation_error`."
173
210
  );
174
211
 
175
212
  // src/charges.ts
176
- var ChargeStatusSchema = z8.enum(["pending", "partially_paid", "confirmed", "expired", "underpaid"]).describe(
213
+ var ChargeStatusSchema = z9.enum(["pending", "partially_paid", "confirmed", "expired", "underpaid"]).describe(
177
214
  "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."
178
215
  );
179
- var SettlementStatusSchema = z8.enum(["pending", "completed", "failed"]).describe(
216
+ var SettlementStatusSchema = z9.enum(["pending", "completed", "failed"]).describe(
180
217
  "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."
181
218
  );
182
219
  var CHARGE_EXPIRES_IN_MIN_SECONDS = 60;
183
220
  var CHARGE_EXPIRES_IN_MAX_SECONDS = 3600;
184
221
  var CHARGE_ACCEPTED_PAYMENTS_MAX = 14;
185
- var AcceptedPaymentSchema = z8.object({
222
+ var AcceptedPaymentSchema = z9.object({
186
223
  token: TokenSchema,
187
224
  network: NetworkSchema
188
225
  });
189
- var AcceptedPaymentsSchema = z8.array(AcceptedPaymentSchema).min(1, "At least one accepted payment is required.").max(CHARGE_ACCEPTED_PAYMENTS_MAX).superRefine((pairs, ctx) => {
226
+ var AcceptedPaymentsSchema = z9.array(AcceptedPaymentSchema).min(1, "At least one accepted payment is required.").max(CHARGE_ACCEPTED_PAYMENTS_MAX).superRefine((pairs, ctx) => {
190
227
  const seen = /* @__PURE__ */ new Set();
191
228
  pairs.forEach((pair, index) => {
192
229
  const key = `${pair.token}:${pair.network}`;
193
230
  if (seen.has(key)) {
194
231
  ctx.addIssue({
195
- code: z8.ZodIssueCode.custom,
232
+ code: z9.ZodIssueCode.custom,
196
233
  message: `Duplicate accepted payment: ${pair.token} on ${pair.network}.`,
197
234
  path: [index]
198
235
  });
@@ -200,7 +237,7 @@ var AcceptedPaymentsSchema = z8.array(AcceptedPaymentSchema).min(1, "At least on
200
237
  seen.add(key);
201
238
  if (!OPERATIONAL_NETWORKS.includes(pair.network)) {
202
239
  ctx.addIssue({
203
- code: z8.ZodIssueCode.custom,
240
+ code: z9.ZodIssueCode.custom,
204
241
  message: `Network "${pair.network}" isn't live yet \u2014 only ${OPERATIONAL_NETWORKS.join(", ")} today.`,
205
242
  path: [index, "network"]
206
243
  });
@@ -210,32 +247,32 @@ var AcceptedPaymentsSchema = z8.array(AcceptedPaymentSchema).min(1, "At least on
210
247
  `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\`.`
211
248
  );
212
249
  var CHARGE_SPLIT_RECIPIENTS_MAX = 5;
213
- var SplitRecipientSchema = z8.object({
214
- address: z8.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."),
215
- percent: z8.number().positive().max(100).describe(
250
+ var SplitRecipientSchema = z9.object({
251
+ address: z9.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."),
252
+ percent: z9.number().positive().max(100).describe(
216
253
  "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."
217
254
  ),
218
- label: z8.string().min(1).max(64).optional().describe(
255
+ label: z9.string().min(1).max(64).optional().describe(
219
256
  'Free-form label for your own bookkeeping (e.g. `"supplier"`, `"sales rep"`) \u2014 echoed back unchanged, never interpreted by Klappay.'
220
257
  )
221
258
  });
222
- var SplitRecipientInputSchema = z8.object({
223
- recipientId: z8.string().describe(
259
+ var SplitRecipientInputSchema = z9.object({
260
+ recipientId: z9.string().describe(
224
261
  "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."
225
262
  ),
226
- percent: z8.number().positive().max(100).describe(
263
+ percent: z9.number().positive().max(100).describe(
227
264
  "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."
228
265
  ),
229
- label: z8.string().min(1).max(64).optional().describe(
266
+ label: z9.string().min(1).max(64).optional().describe(
230
267
  '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.'
231
268
  )
232
269
  });
233
- var SplitRecipientsInputSchema = z8.array(SplitRecipientInputSchema).max(CHARGE_SPLIT_RECIPIENTS_MAX).superRefine((recipients, ctx) => {
270
+ var SplitRecipientsInputSchema = z9.array(SplitRecipientInputSchema).max(CHARGE_SPLIT_RECIPIENTS_MAX).superRefine((recipients, ctx) => {
234
271
  const seen = /* @__PURE__ */ new Set();
235
272
  recipients.forEach((recipient, index) => {
236
273
  if (seen.has(recipient.recipientId)) {
237
274
  ctx.addIssue({
238
- code: z8.ZodIssueCode.custom,
275
+ code: z9.ZodIssueCode.custom,
239
276
  message: `Duplicate split recipientId: ${recipient.recipientId}.`,
240
277
  path: [index, "recipientId"]
241
278
  });
@@ -246,79 +283,82 @@ var SplitRecipientsInputSchema = z8.array(SplitRecipientInputSchema).max(CHARGE_
246
283
  `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\`.`
247
284
  );
248
285
  var CHARGE_AMOUNT_MAX = 999999999999;
249
- var CreateChargeSchema = z8.object({
250
- amount: z8.number().positive().max(CHARGE_AMOUNT_MAX).describe(
286
+ var CreateChargeSchema = z9.object({
287
+ amount: z9.number().positive().max(CHARGE_AMOUNT_MAX).describe(
251
288
  "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."
252
289
  ),
253
- currency: z8.literal("USD").default("USD").describe("Always `USD` today \u2014 the only supported currency."),
290
+ currency: z9.literal("USD").default("USD").describe("Always `USD` today \u2014 the only supported currency."),
254
291
  acceptedPayments: AcceptedPaymentsSchema,
255
- expiresIn: z8.number().int().min(CHARGE_EXPIRES_IN_MIN_SECONDS).max(CHARGE_EXPIRES_IN_MAX_SECONDS).describe(
292
+ expiresIn: z9.number().int().min(CHARGE_EXPIRES_IN_MIN_SECONDS).max(CHARGE_EXPIRES_IN_MAX_SECONDS).describe(
256
293
  "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."
257
294
  ),
258
- idempotencyKey: z8.string().min(1).max(255).optional().describe(
295
+ idempotencyKey: z9.string().min(1).max(255).optional().describe(
259
296
  "Scoped to your tenant. Replaying the same key returns the original charge unchanged instead of creating a duplicate \u2014 safe to retry a request after a timeout without double-charging."
260
297
  ),
261
- externalRef: z8.string().min(1).max(255).optional().describe(
298
+ externalRef: z9.string().min(1).max(255).optional().describe(
262
299
  "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."
263
300
  ),
264
- source: z8.string().min(1).max(64).optional().describe(
301
+ source: z9.string().min(1).max(64).optional().describe(
265
302
  '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.'
266
303
  ),
267
304
  metadata: MetadataWithKlappaySchema.optional(),
268
- redirectUrl: z8.string().url().refine((value) => /^https?:\/\//.test(value), "must use http or https").optional().describe(
305
+ redirectUrl: z9.string().url().refine((value) => /^https?:\/\//.test(value), "must use http or https").optional().describe(
269
306
  "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."
270
307
  ),
271
308
  splitRecipients: SplitRecipientsInputSchema.optional()
272
309
  });
273
- var ChargeSchema = z8.object({
274
- id: z8.string().describe("Klappay-generated id, e.g. `ch_...`. Use this to look up the charge later."),
275
- amount: z8.number().describe("The amount originally requested, in `currency` units (up to 6 decimal places)."),
276
- amountReceived: z8.number().nullable().describe(
310
+ var ChargeSchema = z9.object({
311
+ id: z9.string().describe("Klappay-generated id, e.g. `ch_...`. Use this to look up the charge later."),
312
+ amount: z9.number().describe("The amount originally requested, in `currency` units (up to 6 decimal places)."),
313
+ amountReceived: z9.number().nullable().describe(
277
314
  "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`."
278
315
  ),
279
- isOverpaid: z8.boolean().describe(
316
+ isOverpaid: z9.boolean().describe(
280
317
  "`true` if `amountReceived` ended up greater than `amount`. Klappay never refunds the difference automatically \u2014 see the docs for why."
281
318
  ),
282
- currency: z8.string().describe("Always `USD` today \u2014 the only supported currency."),
283
- acceptedPayments: z8.array(AcceptedPaymentSchema).describe(
319
+ currency: z9.string().describe("Always `USD` today \u2014 the only supported currency."),
320
+ acceptedPayments: z9.array(AcceptedPaymentSchema).describe(
284
321
  "Every `(token, network)` pair this charge was configured to accept, unchanged after creation."
285
322
  ),
286
- paidWith: z8.array(AcceptedPaymentSchema).describe(
323
+ paidWith: z9.array(AcceptedPaymentSchema).describe(
287
324
  "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`."
288
325
  ),
289
- address: z8.string().describe(
326
+ swapAlternatives: z9.array(SwapAlternativeSchema).describe(
327
+ "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`)."
328
+ ),
329
+ address: z9.string().describe(
290
330
  "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."
291
331
  ),
292
332
  status: ChargeStatusSchema,
293
333
  settlementStatus: SettlementStatusSchema.nullable(),
294
334
  environment: EnvironmentSchema,
295
- apiKeyId: z8.string().nullable().describe(
335
+ apiKeyId: z9.string().nullable().describe(
296
336
  "Which of your API keys created this charge. `null` for a charge created before this field existed."
297
337
  ),
298
- txHash: z8.string().nullable().describe(
338
+ txHash: z9.string().nullable().describe(
299
339
  "Transaction hash of the most recent transfer detected for this charge. `null` until a payment is detected."
300
340
  ),
301
- externalRef: z8.string().nullable(),
302
- source: z8.string().nullable(),
341
+ externalRef: z9.string().nullable(),
342
+ source: z9.string().nullable(),
303
343
  metadata: MetadataWithKlappaySchema.nullable(),
304
- redirectUrl: z8.string().nullable().describe("Echoes the `redirectUrl` set at creation, if any. `null` if none was set."),
305
- checkoutUrl: z8.string().nullable().describe(
344
+ redirectUrl: z9.string().nullable().describe("Echoes the `redirectUrl` set at creation, if any. `null` if none was set."),
345
+ checkoutUrl: z9.string().nullable().describe(
306
346
  "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."
307
347
  ),
308
- splitRecipients: z8.array(SplitRecipientSchema).describe("Echoes whatever extra split recipients were set at creation \u2014 empty array if none."),
309
- createdAt: z8.string().datetime(),
310
- expiresAt: z8.string().datetime().describe(
348
+ splitRecipients: z9.array(SplitRecipientSchema).describe("Echoes whatever extra split recipients were set at creation \u2014 empty array if none."),
349
+ createdAt: z9.string().datetime(),
350
+ expiresAt: z9.string().datetime().describe(
311
351
  "When this charge stops accepting payment, if still `pending`/`partially_paid` by then."
312
352
  ),
313
- confirmedAt: z8.string().datetime().nullable().describe("When `status` first reached `confirmed`. `null` until then."),
314
- settledAt: z8.string().datetime().nullable().describe(
353
+ confirmedAt: z9.string().datetime().nullable().describe("When `status` first reached `confirmed`. `null` until then."),
354
+ settledAt: z9.string().datetime().nullable().describe(
315
355
  "When `settlementStatus` first reached `completed` \u2014 the merchant's wallet actually has the funds. `null` until then, including while `settlementStatus` is `pending`/`failed`."
316
356
  ),
317
- lastActivityAt: z8.string().datetime().describe(
357
+ lastActivityAt: z9.string().datetime().describe(
318
358
  "When a transfer was last credited toward this charge, or `createdAt` if none has arrived yet."
319
359
  )
320
360
  });
321
- var ListChargesSchema = z8.object({
361
+ var ListChargesSchema = z9.object({
322
362
  status: ChargeStatusSchema.optional(),
323
363
  token: TokenSchema.optional().describe(
324
364
  "Filters on `paidWith.token` \u2014 the pair actually paid, not accepted."
@@ -327,13 +367,13 @@ var ListChargesSchema = z8.object({
327
367
  "Filters on `paidWith.network` \u2014 the pair actually paid, not accepted."
328
368
  ),
329
369
  environment: EnvironmentSchema.optional(),
330
- since: z8.string().datetime().optional().describe(
370
+ since: z9.string().datetime().optional().describe(
331
371
  "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."
332
372
  ),
333
- isOverpaid: z8.enum(["true", "false"]).transform((v) => v === "true").optional()
373
+ isOverpaid: z9.enum(["true", "false"]).transform((v) => v === "true").optional()
334
374
  }).extend(PaginationQuerySchema.shape);
335
375
  var PaginatedChargesSchema = paginatedSchema(ChargeSchema);
336
- var GetChargeQrCodeQuerySchema = z8.object({
376
+ var GetChargeQrCodeQuerySchema = z9.object({
337
377
  token: TokenSchema.optional().describe(
338
378
  "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."
339
379
  ),
@@ -341,61 +381,61 @@ var GetChargeQrCodeQuerySchema = z8.object({
341
381
  });
342
382
 
343
383
  // src/distributions.ts
344
- import { z as z9 } from "zod";
345
- var SplitDistributionStatusSchema = z9.enum(["pending", "processing", "completed", "failed"]).describe(
384
+ import { z as z10 } from "zod";
385
+ var SplitDistributionStatusSchema = z10.enum(["pending", "processing", "completed", "failed"]).describe(
346
386
  "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."
347
387
  );
348
- var PendingDistributionRecipientSchema = z9.object({
349
- address: z9.string().describe("On-chain recipient address."),
350
- percentAllocation: z9.number().describe("This recipient's share of the split, as a percentage (e.g. `99.0991` = 99.0991%).")
388
+ var PendingDistributionRecipientSchema = z10.object({
389
+ address: z10.string().describe("On-chain recipient address."),
390
+ percentAllocation: z10.number().describe("This recipient's share of the split, as a percentage (e.g. `99.0991` = 99.0991%).")
351
391
  });
352
- var PendingDistributionSchema = z9.object({
353
- splitAddress: z9.string().describe("The on-chain 0xSplits address to call `distribute()` on."),
392
+ var PendingDistributionSchema = z10.object({
393
+ splitAddress: z10.string().describe("The on-chain 0xSplits address to call `distribute()` on."),
354
394
  network: NetworkSchema,
355
395
  token: TokenSchema,
356
- recipients: z9.array(PendingDistributionRecipientSchema).describe(
396
+ recipients: z10.array(PendingDistributionRecipientSchema).describe(
357
397
  "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."
358
398
  ),
359
- distributorFeePercent: z9.number().describe(
399
+ distributorFeePercent: z10.number().describe(
360
400
  "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."
361
401
  ),
362
- estimatedRewardAmount: z9.number().describe(
402
+ estimatedRewardAmount: z10.number().describe(
363
403
  "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."
364
404
  ),
365
- availableSince: z9.string().datetime().describe("When this distribution entered its grace period."),
366
- graceEndsAt: z9.string().datetime().describe(
405
+ availableSince: z10.string().datetime().describe("When this distribution entered its grace period."),
406
+ graceEndsAt: z10.string().datetime().describe(
367
407
  "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."
368
408
  )
369
409
  });
370
410
  var PaginatedPendingDistributionsSchema = paginatedSchema(PendingDistributionSchema);
371
- var ListenPendingDistributionsQuerySchema = z9.object({
372
- limit: z9.coerce.number().int().min(0).max(PAGINATION_LIMIT_MAX).default(0).describe(
411
+ var ListenPendingDistributionsQuerySchema = z10.object({
412
+ limit: z10.coerce.number().int().min(0).max(PAGINATION_LIMIT_MAX).default(0).describe(
373
413
  "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."
374
414
  )
375
415
  });
376
- var PendingDistributionEventSchema = z9.discriminatedUnion("type", [
377
- z9.object({
378
- type: z9.literal("distribution.available"),
416
+ var PendingDistributionEventSchema = z10.discriminatedUnion("type", [
417
+ z10.object({
418
+ type: z10.literal("distribution.available"),
379
419
  distribution: PendingDistributionSchema
380
420
  }),
381
- z9.object({
382
- type: z9.literal("distribution.claimed"),
383
- splitAddress: z9.string().describe("No longer claimable \u2014 either settled by someone, or picked up by the worker.")
421
+ z10.object({
422
+ type: z10.literal("distribution.claimed"),
423
+ splitAddress: z10.string().describe("No longer claimable \u2014 either settled by someone, or picked up by the worker.")
384
424
  })
385
425
  ]);
386
426
 
387
427
  // src/metrics.ts
388
- import { z as z10 } from "zod";
389
- var MetricsResourceSchema = z10.enum(["charges", "transactions", "distributions"]).describe(
428
+ import { z as z11 } from "zod";
429
+ var MetricsResourceSchema = z11.enum(["charges", "transactions", "distributions"]).describe(
390
430
  "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."
391
431
  );
392
- var MetricsAggregationSchema = z10.enum(["count", "sum", "avg", "min", "max"]).describe(
432
+ var MetricsAggregationSchema = z11.enum(["count", "sum", "avg", "min", "max"]).describe(
393
433
  "`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."
394
434
  );
395
- var MetricsFilterOperatorSchema = z10.enum(["eq", "neq", "in", "gt", "gte", "lt", "lte"]).describe(
435
+ var MetricsFilterOperatorSchema = z11.enum(["eq", "neq", "in", "gt", "gte", "lt", "lte"]).describe(
396
436
  "`in` expects an array value (max 50 entries); every other operator expects a single scalar."
397
437
  );
398
- var MetricsDateGranularitySchema = z10.enum(["day", "week", "month", "year"]).describe(
438
+ var MetricsDateGranularitySchema = z11.enum(["day", "week", "month", "year"]).describe(
399
439
  "Bucket width for a `date_bucket` `groupBy` entry \u2014 Postgres `date_trunc` semantics (UTC)."
400
440
  );
401
441
  var metricsQueryEnvironmentSchema = EnvironmentSchema.describe(
@@ -408,151 +448,151 @@ var METRICS_QUERY_MAX_GROUP_BY = 3;
408
448
  var METRICS_QUERY_MAX_FILTERS = 20;
409
449
  var METRICS_QUERY_MAX_METRICS = 10;
410
450
  var METRIC_ALIAS_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
411
- var metricAliasSchema = z10.string().min(1).max(64).regex(
451
+ var metricAliasSchema = z11.string().min(1).max(64).regex(
412
452
  METRIC_ALIAS_PATTERN,
413
453
  "Must start with a letter or underscore, and contain only letters, digits, and underscores \u2014 this becomes a SQL column alias."
414
454
  ).optional();
415
- var MetricsFilterValueSchema = z10.union([
416
- z10.string().max(255),
417
- z10.number(),
418
- z10.boolean(),
419
- z10.array(z10.union([z10.string().max(255), z10.number()])).min(1).max(50)
455
+ var MetricsFilterValueSchema = z11.union([
456
+ z11.string().max(255),
457
+ z11.number(),
458
+ z11.boolean(),
459
+ z11.array(z11.union([z11.string().max(255), z11.number()])).min(1).max(50)
420
460
  ]);
421
- var orderBySchema = z10.object({
422
- key: z10.string().min(1).max(64).regex(
461
+ var orderBySchema = z11.object({
462
+ key: z11.string().min(1).max(64).regex(
423
463
  METRIC_ALIAS_PATTERN,
424
464
  "Must start with a letter or underscore, and contain only letters, digits, and underscores \u2014 every valid output column name already looks like this."
425
465
  ).describe(
426
466
  "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."
427
467
  ),
428
- direction: z10.enum(["asc", "desc"])
468
+ direction: z11.enum(["asc", "desc"])
429
469
  }).describe(
430
470
  "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."
431
471
  );
432
- var limitSchema = z10.number().int().min(1).max(METRICS_QUERY_MAX_ROW_LIMIT).default(METRICS_QUERY_DEFAULT_ROW_LIMIT).describe(
472
+ var limitSchema = z11.number().int().min(1).max(METRICS_QUERY_MAX_ROW_LIMIT).default(METRICS_QUERY_DEFAULT_ROW_LIMIT).describe(
433
473
  `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.`
434
474
  );
435
- var ChargesQueryFieldSchema = z10.enum(["status", "source", "apiKeyId", "currency", "isOverpaid", "externalRef"]).describe(
475
+ var ChargesQueryFieldSchema = z11.enum(["status", "source", "apiKeyId", "currency", "isOverpaid", "externalRef"]).describe(
436
476
  "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."
437
477
  );
438
- var ChargesMetricFieldSchema = z10.enum(["amount", "amountReceived", "feePercent"]).describe(
478
+ var ChargesMetricFieldSchema = z11.enum(["amount", "amountReceived", "feePercent"]).describe(
439
479
  "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%."
440
480
  );
441
- var ChargesDateFieldSchema = z10.enum(["createdAt", "confirmedAt", "lastActivityAt", "expiresAt"]).describe(
481
+ var ChargesDateFieldSchema = z11.enum(["createdAt", "confirmedAt", "lastActivityAt", "expiresAt"]).describe(
442
482
  "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."
443
483
  );
444
- var ChargesFilterSchema = z10.object({
484
+ var ChargesFilterSchema = z11.object({
445
485
  field: ChargesQueryFieldSchema,
446
486
  operator: MetricsFilterOperatorSchema,
447
487
  value: MetricsFilterValueSchema
448
488
  });
449
- var ChargesGroupBySchema = z10.union([
450
- z10.object({ type: z10.literal("field"), field: ChargesQueryFieldSchema }),
451
- z10.object({
452
- type: z10.literal("date_bucket"),
489
+ var ChargesGroupBySchema = z11.union([
490
+ z11.object({ type: z11.literal("field"), field: ChargesQueryFieldSchema }),
491
+ z11.object({
492
+ type: z11.literal("date_bucket"),
453
493
  field: ChargesDateFieldSchema,
454
494
  granularity: MetricsDateGranularitySchema
455
495
  })
456
496
  ]);
457
- var ChargesMetricSchema = z10.object({
497
+ var ChargesMetricSchema = z11.object({
458
498
  aggregation: MetricsAggregationSchema,
459
499
  field: ChargesMetricFieldSchema.optional(),
460
500
  alias: metricAliasSchema
461
501
  });
462
- var ChargesMetricsQuerySchema = z10.object({
463
- resource: z10.literal("charges"),
502
+ var ChargesMetricsQuerySchema = z11.object({
503
+ resource: z11.literal("charges"),
464
504
  environment: metricsQueryEnvironmentSchema,
465
- dateRange: z10.object({
505
+ dateRange: z11.object({
466
506
  field: ChargesDateFieldSchema,
467
- from: z10.string().max(64).datetime(),
468
- to: z10.string().max(64).datetime()
507
+ from: z11.string().max(64).datetime(),
508
+ to: z11.string().max(64).datetime()
469
509
  }),
470
- groupBy: z10.array(ChargesGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
471
- metrics: z10.array(ChargesMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
472
- filters: z10.array(ChargesFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
510
+ groupBy: z11.array(ChargesGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
511
+ metrics: z11.array(ChargesMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
512
+ filters: z11.array(ChargesFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
473
513
  orderBy: orderBySchema.optional(),
474
514
  limit: limitSchema
475
515
  });
476
- var TransactionsQueryFieldSchema = z10.enum(["network", "token", "source", "causedTransition"]).describe(
516
+ var TransactionsQueryFieldSchema = z11.enum(["network", "token", "source", "causedTransition"]).describe(
477
517
  "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)."
478
518
  );
479
- var TransactionsMetricFieldSchema = z10.enum(["amount"]).describe("The transfer amount, in the charge's `currency` units.");
480
- var TransactionsDateFieldSchema = z10.enum(["detectedAt"]).describe("When Klappay detected this transfer on-chain (not when it was mined).");
481
- var TransactionsFilterSchema = z10.object({
519
+ var TransactionsMetricFieldSchema = z11.enum(["amount"]).describe("The transfer amount, in the charge's `currency` units.");
520
+ var TransactionsDateFieldSchema = z11.enum(["detectedAt"]).describe("When Klappay detected this transfer on-chain (not when it was mined).");
521
+ var TransactionsFilterSchema = z11.object({
482
522
  field: TransactionsQueryFieldSchema,
483
523
  operator: MetricsFilterOperatorSchema,
484
524
  value: MetricsFilterValueSchema
485
525
  });
486
- var TransactionsGroupBySchema = z10.union([
487
- z10.object({ type: z10.literal("field"), field: TransactionsQueryFieldSchema }),
488
- z10.object({
489
- type: z10.literal("date_bucket"),
526
+ var TransactionsGroupBySchema = z11.union([
527
+ z11.object({ type: z11.literal("field"), field: TransactionsQueryFieldSchema }),
528
+ z11.object({
529
+ type: z11.literal("date_bucket"),
490
530
  field: TransactionsDateFieldSchema,
491
531
  granularity: MetricsDateGranularitySchema
492
532
  })
493
533
  ]);
494
- var TransactionsMetricSchema = z10.object({
534
+ var TransactionsMetricSchema = z11.object({
495
535
  aggregation: MetricsAggregationSchema,
496
536
  field: TransactionsMetricFieldSchema.optional(),
497
537
  alias: metricAliasSchema
498
538
  });
499
- var TransactionsMetricsQuerySchema = z10.object({
500
- resource: z10.literal("transactions"),
539
+ var TransactionsMetricsQuerySchema = z11.object({
540
+ resource: z11.literal("transactions"),
501
541
  environment: metricsQueryEnvironmentSchema,
502
- dateRange: z10.object({
542
+ dateRange: z11.object({
503
543
  field: TransactionsDateFieldSchema,
504
- from: z10.string().max(64).datetime(),
505
- to: z10.string().max(64).datetime()
544
+ from: z11.string().max(64).datetime(),
545
+ to: z11.string().max(64).datetime()
506
546
  }),
507
- groupBy: z10.array(TransactionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
508
- metrics: z10.array(TransactionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
509
- filters: z10.array(TransactionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
547
+ groupBy: z11.array(TransactionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
548
+ metrics: z11.array(TransactionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
549
+ filters: z11.array(TransactionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
510
550
  orderBy: orderBySchema.optional(),
511
551
  limit: limitSchema
512
552
  });
513
- var DistributionsQueryFieldSchema = z10.enum(["status", "network", "token", "distributorAddress"]).describe(
553
+ var DistributionsQueryFieldSchema = z11.enum(["status", "network", "token", "distributorAddress"]).describe(
514
554
  "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."
515
555
  );
516
- var DistributionsMetricFieldSchema = z10.enum(["attempts"]).describe(
556
+ var DistributionsMetricFieldSchema = z11.enum(["attempts"]).describe(
517
557
  "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."
518
558
  );
519
- var DistributionsDateFieldSchema = z10.enum(["createdAt", "processingStartedAt", "completedAt"]).describe(
559
+ var DistributionsDateFieldSchema = z11.enum(["createdAt", "processingStartedAt", "completedAt"]).describe(
520
560
  "`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."
521
561
  );
522
- var DistributionsFilterSchema = z10.object({
562
+ var DistributionsFilterSchema = z11.object({
523
563
  field: DistributionsQueryFieldSchema,
524
564
  operator: MetricsFilterOperatorSchema,
525
565
  value: MetricsFilterValueSchema
526
566
  });
527
- var DistributionsGroupBySchema = z10.union([
528
- z10.object({ type: z10.literal("field"), field: DistributionsQueryFieldSchema }),
529
- z10.object({
530
- type: z10.literal("date_bucket"),
567
+ var DistributionsGroupBySchema = z11.union([
568
+ z11.object({ type: z11.literal("field"), field: DistributionsQueryFieldSchema }),
569
+ z11.object({
570
+ type: z11.literal("date_bucket"),
531
571
  field: DistributionsDateFieldSchema,
532
572
  granularity: MetricsDateGranularitySchema
533
573
  })
534
574
  ]);
535
- var DistributionsMetricSchema = z10.object({
575
+ var DistributionsMetricSchema = z11.object({
536
576
  aggregation: MetricsAggregationSchema,
537
577
  field: DistributionsMetricFieldSchema.optional(),
538
578
  alias: metricAliasSchema
539
579
  });
540
- var DistributionsMetricsQuerySchema = z10.object({
541
- resource: z10.literal("distributions"),
580
+ var DistributionsMetricsQuerySchema = z11.object({
581
+ resource: z11.literal("distributions"),
542
582
  environment: metricsQueryEnvironmentSchema,
543
- dateRange: z10.object({
583
+ dateRange: z11.object({
544
584
  field: DistributionsDateFieldSchema,
545
- from: z10.string().max(64).datetime(),
546
- to: z10.string().max(64).datetime()
585
+ from: z11.string().max(64).datetime(),
586
+ to: z11.string().max(64).datetime()
547
587
  }),
548
- groupBy: z10.array(DistributionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
549
- metrics: z10.array(DistributionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
550
- filters: z10.array(DistributionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
588
+ groupBy: z11.array(DistributionsGroupBySchema).max(METRICS_QUERY_MAX_GROUP_BY).default([]),
589
+ metrics: z11.array(DistributionsMetricSchema).min(1).max(METRICS_QUERY_MAX_METRICS),
590
+ filters: z11.array(DistributionsFilterSchema).max(METRICS_QUERY_MAX_FILTERS).default([]),
551
591
  orderBy: orderBySchema.optional(),
552
592
  limit: limitSchema
553
593
  });
554
594
  var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
555
- var MetricsQuerySchema = z10.discriminatedUnion("resource", [
595
+ var MetricsQuerySchema = z11.discriminatedUnion("resource", [
556
596
  ChargesMetricsQuerySchema,
557
597
  TransactionsMetricsQuerySchema,
558
598
  DistributionsMetricsQuerySchema
@@ -561,7 +601,7 @@ var MetricsQuerySchema = z10.discriminatedUnion("resource", [
561
601
  const to = new Date(input.dateRange.to);
562
602
  if (from >= to) {
563
603
  ctx.addIssue({
564
- code: z10.ZodIssueCode.custom,
604
+ code: z11.ZodIssueCode.custom,
565
605
  message: "`dateRange.from` must be before `dateRange.to`.",
566
606
  path: ["dateRange", "from"]
567
607
  });
@@ -569,7 +609,7 @@ var MetricsQuerySchema = z10.discriminatedUnion("resource", [
569
609
  const spanDays = (to.getTime() - from.getTime()) / ONE_DAY_MS;
570
610
  if (spanDays > MAX_METRICS_QUERY_DATE_RANGE_DAYS) {
571
611
  ctx.addIssue({
572
- code: z10.ZodIssueCode.custom,
612
+ code: z11.ZodIssueCode.custom,
573
613
  message: `\`dateRange\` cannot span more than ${MAX_METRICS_QUERY_DATE_RANGE_DAYS} days.`,
574
614
  path: ["dateRange", "to"]
575
615
  });
@@ -577,7 +617,7 @@ var MetricsQuerySchema = z10.discriminatedUnion("resource", [
577
617
  const dateBucketCount = input.groupBy.filter((entry) => entry.type === "date_bucket").length;
578
618
  if (dateBucketCount > 1) {
579
619
  ctx.addIssue({
580
- code: z10.ZodIssueCode.custom,
620
+ code: z11.ZodIssueCode.custom,
581
621
  message: "At most one `date_bucket` entry is allowed in `groupBy`.",
582
622
  path: ["groupBy"]
583
623
  });
@@ -585,7 +625,7 @@ var MetricsQuerySchema = z10.discriminatedUnion("resource", [
585
625
  input.metrics.forEach((metric, index) => {
586
626
  if (metric.aggregation !== "count" && metric.field === void 0) {
587
627
  ctx.addIssue({
588
- code: z10.ZodIssueCode.custom,
628
+ code: z11.ZodIssueCode.custom,
589
629
  message: "`field` is required unless `aggregation` is `count`.",
590
630
  path: ["metrics", index, "field"]
591
631
  });
@@ -594,7 +634,7 @@ var MetricsQuerySchema = z10.discriminatedUnion("resource", [
594
634
  const aliases = input.metrics.map((metric) => metric.alias).filter((alias) => alias !== void 0);
595
635
  if (new Set(aliases).size !== aliases.length) {
596
636
  ctx.addIssue({
597
- code: z10.ZodIssueCode.custom,
637
+ code: z11.ZodIssueCode.custom,
598
638
  message: "Every `metrics[].alias` must be unique.",
599
639
  path: ["metrics"]
600
640
  });
@@ -603,32 +643,32 @@ var MetricsQuerySchema = z10.discriminatedUnion("resource", [
603
643
  input.metrics.forEach((metric, index) => {
604
644
  if (metric.alias !== void 0 && reservedNames.has(metric.alias)) {
605
645
  ctx.addIssue({
606
- code: z10.ZodIssueCode.custom,
646
+ code: z11.ZodIssueCode.custom,
607
647
  message: `\`alias\` "${metric.alias}" collides with a \`groupBy\` field name (or the reserved word "bucket") \u2014 choose a different alias.`,
608
648
  path: ["metrics", index, "alias"]
609
649
  });
610
650
  }
611
651
  });
612
652
  });
613
- var MetricsQueryResultRowSchema = z10.record(
614
- z10.string(),
615
- z10.union([z10.string(), z10.number(), z10.boolean(), z10.null()])
653
+ var MetricsQueryResultRowSchema = z11.record(
654
+ z11.string(),
655
+ z11.union([z11.string(), z11.number(), z11.boolean(), z11.null()])
616
656
  );
617
- var MetricsQueryResultSchema = z10.object({
618
- data: z10.array(MetricsQueryResultRowSchema),
619
- meta: z10.object({
657
+ var MetricsQueryResultSchema = z11.object({
658
+ data: z11.array(MetricsQueryResultRowSchema),
659
+ meta: z11.object({
620
660
  resource: MetricsResourceSchema,
621
661
  environment: EnvironmentSchema,
622
- rowCount: z10.number().int().describe("Number of rows in `data`."),
623
- truncated: z10.boolean().describe(
662
+ rowCount: z11.number().int().describe("Number of rows in `data`."),
663
+ truncated: z11.boolean().describe(
624
664
  "`true` if more rows matched than `limit` allowed \u2014 `data` holds only the first `limit`."
625
665
  )
626
666
  })
627
667
  });
628
668
 
629
669
  // src/webhook-events.ts
630
- import { z as z11 } from "zod";
631
- var ChargeWebhookEventTypeSchema = z11.enum([
670
+ import { z as z12 } from "zod";
671
+ var ChargeWebhookEventTypeSchema = z12.enum([
632
672
  "charge.created",
633
673
  "charge.partially_paid",
634
674
  "charge.confirmed",
@@ -640,14 +680,14 @@ var ChargeWebhookEventTypeSchema = z11.enum([
640
680
  ]).describe(
641
681
  '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`). Every event in this category carries the full `Charge` object as `data`.'
642
682
  );
643
- var WebhookDeliveryEventTypeSchema = z11.enum(["webhook.delivery_failed", "webhook.delivery_recovered", "webhook.endpoint_unhealthy"]).describe(
683
+ var WebhookDeliveryEventTypeSchema = z12.enum(["webhook.delivery_failed", "webhook.delivery_recovered", "webhook.endpoint_unhealthy"]).describe(
644
684
  "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`)."
645
685
  );
646
- var WebhookEventTypeSchema = z11.union([
686
+ var WebhookEventTypeSchema = z12.union([
647
687
  ChargeWebhookEventTypeSchema,
648
688
  WebhookDeliveryEventTypeSchema
649
689
  ]);
650
- var WebhookCategorySchema = z11.enum(["payments", "webhooks"]).describe(
690
+ var WebhookCategorySchema = z12.enum(["payments", "webhooks"]).describe(
651
691
  "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."
652
692
  );
653
693
  function buildCategoryMap() {
@@ -675,101 +715,101 @@ var TriggerableChargeEventSchema = ChargeWebhookEventTypeSchema.exclude([
675
715
  );
676
716
 
677
717
  // src/webhooks.ts
678
- import { z as z12 } from "zod";
718
+ import { z as z13 } from "zod";
679
719
  var WEBHOOK_EVENTS_WILDCARD = "*";
680
- var CreateWebhookSchema = z12.object({
681
- url: z12.string().max(2048).url().describe(
720
+ var CreateWebhookSchema = z13.object({
721
+ url: z13.string().max(2048).url().describe(
682
722
  "Must be HTTPS and resolve to a public address \u2014 private/internal IPs are rejected."
683
723
  ),
684
- events: z12.array(z12.union([WebhookEventTypeSchema, z12.literal(WEBHOOK_EVENTS_WILDCARD)])).max(Object.keys(EVENT_CATEGORY_MAP).length + 1).default([]).describe(
724
+ events: z13.array(z13.union([WebhookEventTypeSchema, z13.literal(WEBHOOK_EVENTS_WILDCARD)])).max(Object.keys(EVENT_CATEGORY_MAP).length + 1).default([]).describe(
685
725
  '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.'
686
726
  ),
687
- eventCategories: z12.array(WebhookCategorySchema).max(WebhookCategorySchema.options.length).default([]).describe(
727
+ eventCategories: z13.array(WebhookCategorySchema).max(WebhookCategorySchema.options.length).default([]).describe(
688
728
  "Subscribe to every event in these categories. At least one of `events` or `eventCategories` is required."
689
729
  ),
690
- excludeEvents: z12.array(WebhookEventTypeSchema).max(Object.keys(EVENT_CATEGORY_MAP).length).default([]).describe(
730
+ excludeEvents: z13.array(WebhookEventTypeSchema).max(Object.keys(EVENT_CATEGORY_MAP).length).default([]).describe(
691
731
  'Event types to exclude even if selected via `events: ["*"]` or `eventCategories`.'
692
732
  )
693
733
  }).refine((v) => v.events.length > 0 || v.eventCategories.length > 0, {
694
734
  message: "must select at least one event via `events` or `eventCategories`",
695
735
  path: ["events"]
696
736
  });
697
- var WebhookSchema = z12.object({
698
- id: z12.string(),
737
+ var WebhookSchema = z13.object({
738
+ id: z13.string(),
699
739
  environment: EnvironmentSchema.nullable().describe(
700
740
  "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)."
701
741
  ),
702
- url: z12.string(),
703
- events: z12.array(WebhookEventTypeSchema),
704
- eventCategories: z12.array(WebhookCategorySchema),
705
- excludeEvents: z12.array(WebhookEventTypeSchema),
706
- isWildcard: z12.boolean(),
707
- secret: z12.string().describe(
742
+ url: z13.string(),
743
+ events: z13.array(WebhookEventTypeSchema),
744
+ eventCategories: z13.array(WebhookCategorySchema),
745
+ excludeEvents: z13.array(WebhookEventTypeSchema),
746
+ isWildcard: z13.boolean(),
747
+ secret: z13.string().describe(
708
748
  "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."
709
749
  ),
710
- createdAt: z12.string().datetime()
750
+ createdAt: z13.string().datetime()
711
751
  });
712
752
  var WebhookListItemSchema = WebhookSchema.omit({ secret: true }).extend({
713
- hint: z12.string().describe("A truncated, safe-to-display form of the secret (e.g. `whsec_...ab12`).")
753
+ hint: z13.string().describe("A truncated, safe-to-display form of the secret (e.g. `whsec_...ab12`).")
714
754
  });
715
- var WebhookPayloadSchema = z12.object({
716
- id: z12.string().describe(
755
+ var WebhookPayloadSchema = z13.object({
756
+ id: z13.string().describe(
717
757
  "Unique id for this specific delivery \u2014 also sent as the `X-Klappay-Delivery` header."
718
758
  ),
719
759
  event: WebhookEventTypeSchema,
720
- createdAt: z12.string().datetime(),
721
- data: z12.unknown().describe(
760
+ createdAt: z13.string().datetime(),
761
+ data: z13.unknown().describe(
722
762
  "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."
723
763
  )
724
764
  });
725
- var WebhookDeliveryStatusSchema = z12.enum(["pending", "delivered", "failed"]);
726
- var WebhookDeliverySchema = z12.object({
727
- id: z12.string(),
728
- webhookId: z12.string(),
765
+ var WebhookDeliveryStatusSchema = z13.enum(["pending", "delivered", "failed"]);
766
+ var WebhookDeliverySchema = z13.object({
767
+ id: z13.string(),
768
+ webhookId: z13.string(),
729
769
  event: WebhookEventTypeSchema,
730
770
  status: WebhookDeliveryStatusSchema.describe(
731
771
  "`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."
732
772
  ),
733
- attempts: z12.number(),
734
- responseCode: z12.number().nullable().describe(
773
+ attempts: z13.number(),
774
+ responseCode: z13.number().nullable().describe(
735
775
  "HTTP status your endpoint returned on the most recent attempt. `null` if every attempt failed to connect at all."
736
776
  ),
737
- nextRetryAt: z12.string().datetime().nullable(),
738
- deliveredAt: z12.string().datetime().nullable(),
739
- createdAt: z12.string().datetime()
777
+ nextRetryAt: z13.string().datetime().nullable(),
778
+ deliveredAt: z13.string().datetime().nullable(),
779
+ createdAt: z13.string().datetime()
740
780
  });
741
781
  var ListWebhookDeliveriesSchema = PaginationQuerySchema;
742
782
  var PaginatedWebhookDeliveriesSchema = paginatedSchema(WebhookDeliverySchema);
743
783
 
744
784
  // src/recipients.ts
745
- import { z as z13 } from "zod";
785
+ import { z as z14 } from "zod";
746
786
  var EVM_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/;
747
- var CreateRecipientSchema = z13.object({
748
- address: z13.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."),
749
- label: z13.string().min(1).max(64).optional().describe('Free-form label for your own bookkeeping (e.g. `"supplier"`) \u2014 never interpreted.')
787
+ var CreateRecipientSchema = z14.object({
788
+ address: z14.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."),
789
+ label: z14.string().min(1).max(64).optional().describe('Free-form label for your own bookkeeping (e.g. `"supplier"`) \u2014 never interpreted.')
750
790
  });
751
- var RecipientSchema = z13.object({
752
- id: z13.string().describe(
791
+ var RecipientSchema = z14.object({
792
+ id: z14.string().describe(
753
793
  "Klappay-generated id, e.g. `rc_...` \u2014 this, not the raw address, is what a charge's `splitRecipients[].recipientId` references."
754
794
  ),
755
795
  environment: EnvironmentSchema,
756
- address: z13.string(),
757
- label: z13.string().nullable(),
758
- payout: z13.boolean().describe(
796
+ address: z14.string(),
797
+ label: z14.string().nullable(),
798
+ payout: z14.boolean().describe(
759
799
  "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`."
760
800
  ),
761
- createdAt: z13.string().datetime()
801
+ createdAt: z14.string().datetime()
762
802
  });
763
- var SetRecipientPayoutSchema = z13.object({
764
- payout: z13.boolean().describe("New payout-eligibility value for this recipient.")
803
+ var SetRecipientPayoutSchema = z14.object({
804
+ payout: z14.boolean().describe("New payout-eligibility value for this recipient.")
765
805
  });
766
806
 
767
807
  // src/timeline.ts
768
- import { z as z14 } from "zod";
769
- var TransactionSourceSchema = z14.enum(["moralis_webhook", "reconciliation_job", "sandbox"]).describe(
808
+ import { z as z15 } from "zod";
809
+ var TransactionSourceSchema = z15.enum(["moralis_webhook", "reconciliation_job", "sandbox"]).describe(
770
810
  "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)."
771
811
  );
772
- var TimelineEventTypeSchema = z14.enum([
812
+ var TimelineEventTypeSchema = z15.enum([
773
813
  "charge.created",
774
814
  "charge.expired",
775
815
  "transaction.detected",
@@ -780,11 +820,11 @@ var TimelineEventTypeSchema = z14.enum([
780
820
  ]).describe(
781
821
  "`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)."
782
822
  );
783
- var TimelineEventSchema = z14.object({
823
+ var TimelineEventSchema = z15.object({
784
824
  type: TimelineEventTypeSchema,
785
- at: z14.string().datetime(),
786
- txHash: z14.string().optional().describe("Present for `transaction.detected` and `split.distributed` events only."),
787
- amount: z14.number().optional().describe(
825
+ at: z15.string().datetime(),
826
+ txHash: z15.string().optional().describe("Present for `transaction.detected` and `split.distributed` events only."),
827
+ amount: z15.number().optional().describe(
788
828
  "Present for `transaction.detected` events only \u2014 the amount that specific transfer carried."
789
829
  ),
790
830
  source: TransactionSourceSchema.optional().describe(
@@ -796,55 +836,111 @@ var TimelineEventSchema = z14.object({
796
836
  network: NetworkSchema.optional().describe(
797
837
  "Present for `transaction.detected` and `split.distributed` events \u2014 which network this specific transfer, or settlement, used."
798
838
  ),
799
- causedTransition: z14.boolean().optional().describe(
839
+ causedTransition: z15.boolean().optional().describe(
800
840
  "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."
801
841
  ),
802
842
  event: WebhookEventTypeSchema.optional().describe(
803
843
  "Present for `webhook.*` events only \u2014 which event type this delivery was for."
804
844
  ),
805
- responseCode: z14.number().nullable().optional().describe(
845
+ responseCode: z15.number().nullable().optional().describe(
806
846
  "Present for `webhook.*` events only \u2014 HTTP status your endpoint returned, or `null` if the request never connected."
807
847
  ),
808
- attempts: z14.number().optional().describe(
848
+ attempts: z15.number().optional().describe(
809
849
  "Present for `webhook.*` events only \u2014 how many delivery attempts have been made so far."
810
850
  )
811
851
  });
812
852
 
813
853
  // src/health.ts
814
- import { z as z15 } from "zod";
815
- var HealthSchema = z15.object({
816
- status: z15.enum(["ok", "error"]).describe(
854
+ import { z as z16 } from "zod";
855
+ var HealthSchema = z16.object({
856
+ status: z16.enum(["ok", "error"]).describe(
817
857
  "`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."
818
858
  ),
819
- version: z15.string(),
820
- timestamp: z15.string().datetime(),
821
- db: z15.enum(["ok", "error"]).describe("Result of a real database connectivity check, not just a process-alive check."),
822
- pendingWebhooks: z15.number().describe("Count of webhook deliveries still awaiting a successful attempt."),
823
- oldestPendingChargeAgeSeconds: z15.number().nullable().describe("Age of the oldest still-unpaid charge, in seconds. `null` if there are none."),
824
- lastMoralisEventAgeSeconds: z15.number().nullable().describe(
859
+ version: z16.string(),
860
+ timestamp: z16.string().datetime(),
861
+ db: z16.enum(["ok", "error"]).describe("Result of a real database connectivity check, not just a process-alive check."),
862
+ pendingWebhooks: z16.number().describe("Count of webhook deliveries still awaiting a successful attempt."),
863
+ oldestPendingChargeAgeSeconds: z16.number().nullable().describe("Age of the oldest still-unpaid charge, in seconds. `null` if there are none."),
864
+ lastMoralisEventAgeSeconds: z16.number().nullable().describe(
825
865
  "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."
826
866
  )
827
867
  });
828
868
 
829
869
  // src/sandbox.ts
830
- import { z as z16 } from "zod";
831
- var SandboxTriggerSchema = z16.object({
870
+ import { z as z17 } from "zod";
871
+ var SandboxTriggerSchema = z17.object({
832
872
  event: TriggerableChargeEventSchema,
833
- amount: z16.number().positive().max(CHARGE_AMOUNT_MAX).optional().describe(
873
+ amount: z17.number().positive().max(CHARGE_AMOUNT_MAX).optional().describe(
834
874
  "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."
835
875
  )
836
876
  });
837
877
 
838
878
  // src/capabilities.ts
839
- import { z as z17 } from "zod";
840
- var CapabilitiesSchema = z17.object({
841
- acceptedPayments: z17.array(AcceptedPaymentSchema).describe(
879
+ import { z as z18 } from "zod";
880
+ var CapabilitiesSchema = z18.object({
881
+ acceptedPayments: z18.array(AcceptedPaymentSchema).describe(
842
882
  "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."
843
883
  )
844
884
  });
885
+
886
+ // src/swap.ts
887
+ import { z as z19 } from "zod";
888
+ var CreateSwapQuoteSchema = z19.object({
889
+ inputToken: AltTokenSchema.describe(
890
+ "Which alt-cryptocurrency the payer wants to send \u2014 must be one of this charge's `swapAlternatives`, or `422 token_not_supported`."
891
+ ),
892
+ inputNetwork: NetworkSchema.describe(
893
+ "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."
894
+ ),
895
+ takerAddress: z19.string().regex(/^0x[0-9a-fA-F]{40}$/, "must be a 20-byte hex address").describe(
896
+ "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."
897
+ )
898
+ });
899
+ var SwapQuoteSchema = z19.object({
900
+ inputToken: AltTokenSchema,
901
+ inputNetwork: NetworkSchema,
902
+ inputAmount: z19.number().describe(
903
+ "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."
904
+ ),
905
+ outputToken: TokenSchema.describe(
906
+ "Which of this charge's `acceptedPayments` tokens the swap resolves to."
907
+ ),
908
+ outputNetwork: NetworkSchema,
909
+ outputAmount: z19.number().describe(
910
+ "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`."
911
+ ),
912
+ fees: z19.object({
913
+ klappayFee: z19.number().describe(
914
+ "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`."
915
+ ),
916
+ zeroExFee: z19.number().nullable().describe(
917
+ "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."
918
+ )
919
+ }).describe(
920
+ "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`."
921
+ ),
922
+ expiresAt: z19.string().datetime().describe(
923
+ "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."
924
+ ),
925
+ transaction: z19.object({
926
+ to: z19.string().describe("Contract address the payer's wallet must send this transaction to."),
927
+ data: z19.string().describe("Calldata \u2014 opaque, must be sent unmodified."),
928
+ value: z19.string().describe(
929
+ "Native currency (ETH/BNB/MATIC/AVAX) to attach, in wei \u2014 `\"0\"` when `inputToken` isn't this network's native currency."
930
+ )
931
+ }).describe(
932
+ "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."
933
+ ),
934
+ permit2: z19.object({ eip712: z19.record(z19.unknown()) }).optional().describe(
935
+ "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. Absent 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."
936
+ )
937
+ });
845
938
  export {
939
+ ALT_TOKEN_ADDRESSES,
940
+ ALT_TOKEN_DECIMALS,
846
941
  API_KEY_SCOPES,
847
942
  AcceptedPaymentSchema,
943
+ AltTokenSchema,
848
944
  ApiKeyScopeSchema,
849
945
  CHARGE_ACCEPTED_PAYMENTS_MAX,
850
946
  CHARGE_AMOUNT_MAX,
@@ -863,6 +959,7 @@ export {
863
959
  CheckoutProductSchema,
864
960
  CreateChargeSchema,
865
961
  CreateRecipientSchema,
962
+ CreateSwapQuoteSchema,
866
963
  CreateWebhookSchema,
867
964
  DistributionsDateFieldSchema,
868
965
  DistributionsMetricFieldSchema,
@@ -912,6 +1009,8 @@ export {
912
1009
  SplitDistributionStatusSchema,
913
1010
  SplitRecipientInputSchema,
914
1011
  SplitRecipientSchema,
1012
+ SwapAlternativeSchema,
1013
+ SwapQuoteSchema,
915
1014
  TOKEN_ADDRESSES,
916
1015
  TOKEN_DECIMALS,
917
1016
  TimelineEventSchema,
@@ -933,6 +1032,7 @@ export {
933
1032
  WebhookPayloadSchema,
934
1033
  WebhookSchema,
935
1034
  findConflictingScopes,
1035
+ listSwapAlternatives,
936
1036
  paginatedSchema
937
1037
  };
938
1038
  //# sourceMappingURL=index.mjs.map