@klappay/types 2.0.1 → 2.0.3

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