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