@payclave/sdk-server 0.1.1 → 0.3.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.cjs CHANGED
@@ -5,14 +5,29 @@ var crypto = require('crypto');
5
5
 
6
6
  // src/index.ts
7
7
  var PAYCLAVE_WEBHOOK_EVENT_TYPES = [
8
+ "invoice.issued",
8
9
  "invoice.paid",
10
+ "invoice.partially_paid",
11
+ "invoice.past_due",
12
+ "invoice.overpaid",
13
+ "invoice.voided",
14
+ "invoice.uncollectible",
15
+ "invoice.refund_recorded",
16
+ "invoice.refund_verified",
17
+ "invoice.refund_failed",
18
+ "invoice.payment_received_after_void",
19
+ "invoice.payment_received_after_uncollectible",
9
20
  "invoice.expired",
21
+ "payment_link.completed",
22
+ "payment_link.expired",
10
23
  "payment.failed",
11
24
  "payment.underpaid",
12
25
  "payment.overpaid"
13
26
  ];
27
+ var PAYCLAVE_RECONCILIATION_SCHEMA_VERSION = "2026-08-29.v1";
14
28
  var PAYCLAVE_API_ERROR_CODES = [
15
29
  "ACCOUNT_SUSPENDED",
30
+ "ACTIVE_MERCHANT_REQUIRED",
16
31
  "API_KEY_FORBIDDEN",
17
32
  "API_KEY_REQUIRED",
18
33
  "AUTH_FORBIDDEN",
@@ -25,6 +40,7 @@ var PAYCLAVE_API_ERROR_CODES = [
25
40
  "GOOGLE_PROFILE_UNAVAILABLE",
26
41
  "GOOGLE_AUTH_STATE_INVALID",
27
42
  "AUTH_PASSWORD_ALREADY_SET",
43
+ "AUTH_PROXY_UNAUTHORIZED",
28
44
  "AUTH_PROVIDER_UNAVAILABLE",
29
45
  "AUTH_REQUIRED",
30
46
  "USE_SOCIAL_LOGIN",
@@ -41,22 +57,73 @@ var PAYCLAVE_API_ERROR_CODES = [
41
57
  "INVALID_WALLET_PAYMENT_ATTEMPT",
42
58
  "INVALID_TX_HASH",
43
59
  "INVALID_WALLET_ADDRESS",
60
+ "MODE_MISMATCH",
61
+ "MEMBERSHIP_REVOKED",
62
+ "MEMBER_ALREADY_EXISTS",
63
+ "MEMBER_LIMIT_REACHED",
64
+ "LAST_OWNER_REQUIRED",
65
+ "INVITATION_ALREADY_PENDING",
66
+ "INVITATION_ALREADY_USED",
67
+ "INVITATION_EMAIL_MISMATCH",
68
+ "INVITATION_EXPIRED",
69
+ "INVITATION_NOT_FOUND",
70
+ "OWNERSHIP_TRANSFER_REQUIRED",
44
71
  "NOT_FOUND",
72
+ "PUBLIC_KEY_FIELD_NOT_ALLOWED",
73
+ "PERMISSION_DENIED",
45
74
  "RATE_LIMIT_EXCEEDED",
75
+ "REAUTH_REQUIRED",
76
+ "STEP_UP_REQUIRED",
46
77
  "REQUEST_ERROR",
78
+ "REQUEST_TOO_LARGE",
47
79
  "SCAN_OR_COPY_UNAVAILABLE",
48
80
  "WALLET_PAYMENTS_UNAVAILABLE",
49
81
  "UNSUPPORTED_DEFAULT_WALLET",
50
82
  "VALIDATION_ERROR",
51
83
  "WEBHOOK_DELIVERY_NOT_FOUND",
84
+ "WEBHOOK_ENDPOINT_DISABLED",
52
85
  "WEBHOOK_ENDPOINT_NOT_FOUND",
53
86
  "WEBHOOK_EVENT_UNSUPPORTED",
87
+ "WEBHOOK_INCIDENT_NOT_FOUND",
54
88
  "WEBHOOK_SIGNATURE_INVALID",
89
+ "SECRET_OVERLAP_ACTIVE",
90
+ "SECRET_OVERLAP_EXPIRED",
55
91
  "CHECKOUT_SESSION_NOT_PAYABLE",
92
+ "EVENT_TYPE_UNSUPPORTED",
93
+ "EVENT_PAYLOAD_TOO_LARGE",
94
+ "JOURNEY_TOKEN_INVALID",
95
+ "EVENT_DUPLICATE",
96
+ "TIMESTAMP_OUT_OF_RANGE",
56
97
  "INVOICE_NOT_FOUND",
57
98
  "INVOICE_STATE_MISMATCH",
58
99
  "INVOICE_TRANSITION_GUARD_FAILED",
59
- "IDEMPOTENCY_KEY_CONFLICT"
100
+ "INVOICE_NOT_EDITABLE",
101
+ "INVOICE_ALREADY_ISSUED",
102
+ "INVOICE_NOT_PAYABLE",
103
+ "INVOICE_PDF_UNAVAILABLE",
104
+ "INVOICE_VERSION_CONFLICT",
105
+ "CURRENCY_MISMATCH",
106
+ "INVALID_TOTAL",
107
+ "CUSTOMER_EMAIL_REQUIRED",
108
+ "IDEMPOTENCY_KEY_CONFLICT",
109
+ "PAYMENT_LINK_NOT_FOUND",
110
+ "PAYMENT_LINK_VERSION_CONFLICT",
111
+ "LINK_INACTIVE",
112
+ "LINK_EXPIRED",
113
+ "LINK_ALREADY_USED",
114
+ "LINK_RESERVED",
115
+ "AMOUNT_OUT_OF_RANGE",
116
+ "FIELD_REQUIRED",
117
+ "FEATURE_UNAVAILABLE",
118
+ "MODE_UNAVAILABLE",
119
+ "CONFIG_CHANGED",
120
+ "RATE_LIMITED",
121
+ "EXPORT_RANGE_TOO_LARGE",
122
+ "EXPORT_NOT_READY",
123
+ "EXPORT_EXPIRED",
124
+ "EXPORT_CANCELLED",
125
+ "EXPORT_SCHEMA_UNSUPPORTED",
126
+ "EXPORT_TOO_LARGE_FOR_SYNC"
60
127
  ];
61
128
  var PAYCLAVE_SERVER_SDK_ERROR_CODES = [
62
129
  "INVALID_SECRET_KEY",
@@ -115,13 +182,15 @@ var PayclaveError = class extends Error {
115
182
  }
116
183
  };
117
184
  var PAYCLAVE_SERVER_SDK_NAME = "payclave-sdk-server";
118
- var PAYCLAVE_SERVER_SDK_VERSION = "0.1.0";
185
+ var PAYCLAVE_SERVER_SDK_VERSION = "0.3.0";
119
186
  var defaultApiBaseUrl = "https://api.payclave.com";
120
187
  var defaultFetcher = (input, init) => fetch(input, init);
121
188
  var secretKeyPattern = /^sk_(test|live)_[A-Za-z0-9_-]+$/;
122
189
  var amountPattern = /^(0|[1-9]\d*)(\.\d{1,6})?$/;
123
190
  var webhookUrlMessage = "Webhook URL must be a valid http or https URL.";
191
+ var webhookRawBodyGuideUrl = "https://www.payclave.com/developers/docs#webhooks";
124
192
  var defaultWebhookToleranceSeconds = 300;
193
+ var defaultTimeoutMs = 3e4;
125
194
  var minExpiryMinutes = 5;
126
195
  var maxExpiryMinutes = 24 * 60;
127
196
  var supportedWebhookEventTypes = new Set(PAYCLAVE_WEBHOOK_EVENT_TYPES);
@@ -134,6 +203,8 @@ var isPlainObject = (value) => {
134
203
  return prototype === Object.prototype || prototype === null;
135
204
  };
136
205
  var isStringOrNull = (value) => typeof value === "string" || value === null;
206
+ var isOptionalString = (value) => value === void 0 || typeof value === "string";
207
+ var isOptionalStringOrNull = (value) => value === void 0 || isStringOrNull(value);
137
208
  var isMetadata = (value) => isPlainObject(value);
138
209
  var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
139
210
  var joinUrl = (baseUrl, path) => `${baseUrl.replace(/\/+$/, "")}${path}`;
@@ -228,6 +299,79 @@ var assertOptionalMetadata = (metadata) => {
228
299
  });
229
300
  }
230
301
  };
302
+ var assertInvoiceDraftFields = (input) => {
303
+ if (!isPlainObject(input.customer) || !Array.isArray(input.lines) || input.lines.length < 1 || input.lines.length > 100) {
304
+ throw new PayclaveError({
305
+ message: "Invoice drafts require a customer object and 1 to 100 lines.",
306
+ code: "INVALID_REQUEST_BODY",
307
+ status: 0
308
+ });
309
+ }
310
+ assertOptionalMetadata(input.metadata);
311
+ assertOptionalExpiry(input.checkoutExpiresInMinutes);
312
+ };
313
+ var assertInvoiceVersion = (version) => {
314
+ if (typeof version !== "number" || !Number.isInteger(version) || version < 1) {
315
+ throw new PayclaveError({
316
+ message: "Invoice version must be a positive integer.",
317
+ code: "INVALID_REQUEST_BODY",
318
+ status: 0
319
+ });
320
+ }
321
+ };
322
+ var assertPaymentLinkFields = (input) => {
323
+ if (!isPlainObject(input) || typeof input.title !== "string" || input.title.trim() === "" || input.mode !== void 0 && input.mode !== "test" && input.mode !== "live" || input.amountType !== "fixed" && input.amountType !== "customer_entered" || input.usageType !== void 0 && input.usageType !== "single_use" && input.usageType !== "reusable" || input.currencyCode !== void 0 && input.currencyCode !== "USDC" && input.currencyCode !== "USDT") {
324
+ throw new PayclaveError({
325
+ message: "Payment link fields are invalid.",
326
+ code: "INVALID_REQUEST_BODY",
327
+ status: 0
328
+ });
329
+ }
330
+ if (input.amountType === "fixed") {
331
+ assertAmount(input.amount);
332
+ } else {
333
+ assertAmount(input.minimumAmount);
334
+ if (input.maximumAmount !== void 0 && input.maximumAmount !== "") {
335
+ assertAmount(input.maximumAmount);
336
+ }
337
+ }
338
+ if (input.collect !== void 0 && (!isPlainObject(input.collect) || Object.values(input.collect).some((value) => typeof value !== "boolean"))) {
339
+ throw new PayclaveError({
340
+ message: "Payment link customer fields must be booleans.",
341
+ code: "INVALID_REQUEST_BODY",
342
+ status: 0
343
+ });
344
+ }
345
+ assertOptionalMetadata(input.metadata);
346
+ };
347
+ var assertPaymentLinkVersion = (version) => {
348
+ if (typeof version !== "number" || !Number.isInteger(version) || version < 1) {
349
+ throw new PayclaveError({
350
+ message: "Payment link version must be a positive integer.",
351
+ code: "INVALID_REQUEST_BODY",
352
+ status: 0
353
+ });
354
+ }
355
+ };
356
+ var paymentLinkBody = (input) => compact({
357
+ mode: input.mode,
358
+ title: input.title,
359
+ description: input.description,
360
+ amountType: input.amountType,
361
+ amount: input.amount,
362
+ minimumAmount: input.minimumAmount,
363
+ maximumAmount: input.maximumAmount,
364
+ currencyCode: input.currencyCode,
365
+ usageType: input.usageType,
366
+ activeAt: input.activeAt,
367
+ expiresAt: input.expiresAt,
368
+ collect: input.collect,
369
+ referencePrefix: input.referencePrefix,
370
+ successUrl: input.successUrl,
371
+ cancelUrl: input.cancelUrl,
372
+ successMessage: input.successMessage,
373
+ metadata: input.metadata
374
+ });
231
375
  var assertIdempotencyKey = (key) => {
232
376
  if (typeof key !== "string" || key.length === 0) {
233
377
  throw new PayclaveError({
@@ -313,6 +457,15 @@ var assertPositiveIntegerLimit = (limit) => {
313
457
  });
314
458
  }
315
459
  };
460
+ var assertReconciliationFormat = (format) => {
461
+ if (format !== "csv" && format !== "json") {
462
+ throw new PayclaveError({
463
+ message: "Reconciliation export format must be csv or json.",
464
+ code: "INVALID_REQUEST_BODY",
465
+ status: 0
466
+ });
467
+ }
468
+ };
316
469
  var serializeBody = (body) => {
317
470
  try {
318
471
  return JSON.stringify(body);
@@ -365,6 +518,98 @@ var parseResponse = async (response, guard) => {
365
518
  }
366
519
  return body.data;
367
520
  };
521
+ var parseInvoicePDFResponse = async (response) => {
522
+ const fallbackRequestId = response.headers.get("X-Request-ID");
523
+ if (!response.ok) {
524
+ const body = await response.json().catch(() => null);
525
+ if (isFailureResponse(body)) {
526
+ throw new PayclaveError({
527
+ message: body.error.message,
528
+ code: body.error.code,
529
+ status: response.status,
530
+ requestId: body.meta?.requestId ?? fallbackRequestId,
531
+ details: body.error.details
532
+ });
533
+ }
534
+ throw new PayclaveError({
535
+ message: "Payclave returned an invalid response.",
536
+ code: "INVALID_RESPONSE",
537
+ status: response.status,
538
+ requestId: fallbackRequestId
539
+ });
540
+ }
541
+ if (response.headers.get("content-type")?.split(";", 1)[0].trim() !== "application/pdf") {
542
+ throw new PayclaveError({
543
+ message: "Payclave returned an invalid invoice PDF response.",
544
+ code: "INVALID_RESPONSE",
545
+ status: response.status,
546
+ requestId: fallbackRequestId
547
+ });
548
+ }
549
+ const bytes = new Uint8Array(await response.arrayBuffer());
550
+ if (bytes.length < 5 || String.fromCharCode(...bytes.slice(0, 5)) !== "%PDF-") {
551
+ throw new PayclaveError({
552
+ message: "Payclave returned invalid invoice PDF bytes.",
553
+ code: "INVALID_RESPONSE",
554
+ status: response.status,
555
+ requestId: fallbackRequestId
556
+ });
557
+ }
558
+ const disposition = response.headers.get("content-disposition") ?? "";
559
+ const filenameMatch = disposition.match(
560
+ /filename=(?:"([^"\r\n/\\]+\.pdf)"|([^;\s\r\n/\\]+\.pdf))/i
561
+ );
562
+ const filename = filenameMatch?.[1] ?? filenameMatch?.[2] ?? "payclave-invoice.pdf";
563
+ return {
564
+ bytes,
565
+ contentType: "application/pdf",
566
+ filename,
567
+ requestId: fallbackRequestId
568
+ };
569
+ };
570
+ var parseReconciliationDownloadResponse = async (response) => {
571
+ const requestId = response.headers.get("X-Request-ID");
572
+ if (!response.ok) {
573
+ const body = await response.json().catch(() => null);
574
+ if (isFailureResponse(body)) {
575
+ throw new PayclaveError({
576
+ message: body.error.message,
577
+ code: body.error.code,
578
+ status: response.status,
579
+ requestId: body.meta?.requestId ?? requestId,
580
+ details: body.error.details
581
+ });
582
+ }
583
+ throw new PayclaveError({
584
+ message: "Payclave returned an invalid response.",
585
+ code: "INVALID_RESPONSE",
586
+ status: response.status,
587
+ requestId
588
+ });
589
+ }
590
+ if (response.headers.get("content-type")?.split(";", 1)[0].trim() !== "application/zip" || !response.body) {
591
+ throw new PayclaveError({
592
+ message: "Payclave returned an invalid reconciliation archive response.",
593
+ code: "INVALID_RESPONSE",
594
+ status: response.status,
595
+ requestId
596
+ });
597
+ }
598
+ const disposition = response.headers.get("content-disposition") ?? "";
599
+ const filenameMatch = disposition.match(
600
+ /filename=(?:"([^"\r\n/\\]+\.zip)"|([^;\s\r\n/\\]+\.zip))/i
601
+ );
602
+ const rawSize = response.headers.get("content-length");
603
+ const parsedSize = rawSize === null ? Number.NaN : Number(rawSize);
604
+ return {
605
+ stream: response.body,
606
+ contentType: "application/zip",
607
+ filename: filenameMatch?.[1] ?? filenameMatch?.[2] ?? "payclave-reconciliation.zip",
608
+ byteSize: Number.isSafeInteger(parsedSize) && parsedSize >= 0 ? parsedSize : null,
609
+ sha256: response.headers.get("X-Payclave-Content-SHA256"),
610
+ requestId
611
+ };
612
+ };
368
613
  var runFetch = async ({
369
614
  fetcher,
370
615
  url,
@@ -438,32 +683,45 @@ var isCreatedCheckoutSession = (value) => {
438
683
  if (!isRecord(value)) {
439
684
  return false;
440
685
  }
441
- return typeof value.id === "string" && typeof value.checkoutId === "string" && value.object === "checkout_session" && typeof value.mode === "string" && value.status === "pending" && typeof value.invoiceId === "string" && typeof value.invoiceNumber === "string" && typeof value.amountDue === "string" && typeof value.amountReceived === "string" && typeof value.currencyCode === "string" && typeof value.chainId === "number" && typeof value.tokenSymbol === "string" && typeof value.tokenContract === "string" && typeof value.settlementWalletAddress === "string" && isStringOrNull(value.externalReference) && isStringOrNull(value.customerEmail) && isMetadata(value.metadata) && typeof value.checkoutUrl === "string" && typeof value.expiresAt === "string" && typeof value.createdAt === "string";
686
+ return typeof value.id === "string" && typeof value.checkoutId === "string" && value.object === "checkout_session" && typeof value.mode === "string" && isOptionalString(value.sourceType) && value.status === "pending" && typeof value.collectionState === "string" && typeof value.invoiceId === "string" && typeof value.invoiceNumber === "string" && typeof value.amountDue === "string" && typeof value.amountReceived === "string" && typeof value.total === "string" && typeof value.customerAmountPaid === "string" && typeof value.customerAmountRemaining === "string" && typeof value.currencyCode === "string" && typeof value.chainId === "number" && typeof value.tokenSymbol === "string" && typeof value.tokenContract === "string" && typeof value.settlementWalletAddress === "string" && isStringOrNull(value.externalReference) && isStringOrNull(value.customerEmail) && isMetadata(value.metadata) && typeof value.checkoutUrl === "string" && typeof value.expiresAt === "string" && typeof value.createdAt === "string";
442
687
  };
443
688
  var isCheckoutSession = (value) => {
444
689
  if (!isRecord(value)) {
445
690
  return false;
446
691
  }
447
- return typeof value.id === "string" && typeof value.checkoutId === "string" && value.object === "checkout_session" && typeof value.mode === "string" && typeof value.status === "string" && isStringOrNull(value.invoiceId) && isStringOrNull(value.invoiceNumber) && typeof value.amountDue === "string" && typeof value.amountReceived === "string" && typeof value.currencyCode === "string" && typeof value.chainId === "number" && typeof value.tokenSymbol === "string" && typeof value.tokenContract === "string" && typeof value.settlementWalletAddress === "string" && isStringOrNull(value.externalReference) && isStringOrNull(value.customerEmail) && isMetadata(value.metadata) && typeof value.checkoutUrl === "string" && typeof value.expiresAt === "string" && isStringOrNull(value.completedAt) && typeof value.createdAt === "string";
692
+ return typeof value.id === "string" && typeof value.checkoutId === "string" && value.object === "checkout_session" && typeof value.mode === "string" && isOptionalString(value.sourceType) && typeof value.status === "string" && typeof value.collectionState === "string" && isStringOrNull(value.invoiceId) && isStringOrNull(value.invoiceNumber) && typeof value.amountDue === "string" && typeof value.amountReceived === "string" && typeof value.total === "string" && typeof value.customerAmountPaid === "string" && typeof value.customerAmountRemaining === "string" && typeof value.currencyCode === "string" && typeof value.chainId === "number" && typeof value.tokenSymbol === "string" && typeof value.tokenContract === "string" && typeof value.settlementWalletAddress === "string" && isStringOrNull(value.externalReference) && isStringOrNull(value.customerEmail) && isMetadata(value.metadata) && typeof value.checkoutUrl === "string" && typeof value.expiresAt === "string" && isStringOrNull(value.completedAt) && typeof value.createdAt === "string";
448
693
  };
449
694
  var isInvoice = (value) => {
450
695
  if (!isRecord(value)) {
451
696
  return false;
452
697
  }
453
- return typeof value.id === "string" && typeof value.invoiceNumber === "string" && value.object === "invoice" && typeof value.mode === "string" && typeof value.status === "string" && typeof value.amountDue === "string" && typeof value.amountReceived === "string" && typeof value.platformFee === "string" && typeof value.netAmount === "string" && typeof value.currencyCode === "string" && typeof value.chainId === "number" && typeof value.tokenContract === "string" && typeof value.settlementWalletAddress === "string" && isStringOrNull(value.externalReference) && isMetadata(value.metadata) && typeof value.expiresAt === "string" && isStringOrNull(value.paidAt) && isStringOrNull(value.cancelledAt) && typeof value.createdAt === "string";
698
+ return typeof value.id === "string" && isStringOrNull(value.invoiceNumber) && value.object === "invoice" && typeof value.mode === "string" && typeof value.status === "string" && typeof value.collectionState === "string" && typeof value.subtotal === "string" && typeof value.discountTotal === "string" && typeof value.taxTotal === "string" && typeof value.total === "string" && typeof value.customerAmountPaid === "string" && typeof value.customerAmountRemaining === "string" && typeof value.expectedMerchantSettlement === "string" && typeof value.merchantAmountSettled === "string" && typeof value.overpaymentAmount === "string" && typeof value.migrationState === "string" && typeof value.amountDue === "string" && typeof value.amountReceived === "string" && typeof value.platformFee === "string" && typeof value.netAmount === "string" && typeof value.currencyCode === "string" && typeof value.chainId === "number" && typeof value.tokenContract === "string" && typeof value.settlementWalletAddress === "string" && isStringOrNull(value.externalReference) && isMetadata(value.metadata) && isStringOrNull(value.expiresAt) && isStringOrNull(value.paidAt) && isStringOrNull(value.cancelledAt) && isOptionalStringOrNull(value.voidedAt) && isOptionalStringOrNull(value.uncollectibleAt) && typeof value.createdAt === "string" && isOptionalString(value.internalId) && isOptionalString(value.sourceType) && (value.version === void 0 || typeof value.version === "number") && isOptionalString(value.calculationVersion) && (value.customer === void 0 || isRecord(value.customer)) && (value.lines === void 0 || Array.isArray(value.lines)) && (value.discount === void 0 || value.discount === null || isRecord(value.discount)) && (value.taxes === void 0 || Array.isArray(value.taxes)) && isOptionalStringOrNull(value.dueAt) && isOptionalStringOrNull(value.issuedAt) && isOptionalStringOrNull(value.publicToken) && (value.hostedInvoiceEnabled === void 0 || typeof value.hostedInvoiceEnabled === "boolean") && isOptionalStringOrNull(value.hostedInvoiceUrl) && (value.checkoutSessions === void 0 || Array.isArray(value.checkoutSessions)) && (value.payments === void 0 || Array.isArray(value.payments)) && (value.adjustments === void 0 || Array.isArray(value.adjustments)) && (value.deliveries === void 0 || Array.isArray(value.deliveries)) && (value.reminderSchedule === void 0 || isRecord(value.reminderSchedule)) && isOptionalStringOrNull(value.remindersPausedAt) && isOptionalStringOrNull(value.lastReminderAt) && isOptionalStringOrNull(value.nextReminderAt) && isOptionalStringOrNull(value.lastSentAt) && isOptionalString(value.updatedAt) && isOptionalStringOrNull(value.lastActivityAt);
454
699
  };
700
+ var isInvoiceCheckoutSessionCreated = (value) => isRecord(value) && typeof value.invoiceId === "string" && typeof value.invoiceNumber === "string" && typeof value.checkoutSessionId === "string" && typeof value.checkoutUrl === "string" && typeof value.amountDue === "string" && typeof value.currencyCode === "string" && typeof value.expiresAt === "string";
701
+ var isRefundReferenceResult = (value) => isRecord(value) && isRecord(value.adjustment) && isInvoice(value.invoice);
702
+ var isRefundDecision = (value) => isRecord(value) && typeof value.allowed === "boolean" && typeof value.requiresApproval === "boolean" && typeof value.refundableAmount === "string" && typeof value.overpaidAmount === "string" && Array.isArray(value.warnings);
703
+ var isInvoiceList = (value) => isRecord(value) && Array.isArray(value.items) && value.items.every(isInvoice) && typeof value.hasMore === "boolean" && isStringOrNull(value.nextCursor);
704
+ var isPaymentLinkCollect = (value) => isRecord(value) && typeof value.email === "boolean" && typeof value.name === "boolean" && typeof value.reference === "boolean";
705
+ var isPaymentLink = (value) => isRecord(value) && typeof value.id === "string" && value.object === "payment_link" && typeof value.publicId === "string" && typeof value.url === "string" && typeof value.merchantId === "string" && typeof value.mode === "string" && typeof value.status === "string" && typeof value.version === "number" && typeof value.title === "string" && typeof value.description === "string" && (value.amountType === "fixed" || value.amountType === "customer_entered") && isStringOrNull(value.amount) && isStringOrNull(value.minimumAmount) && isStringOrNull(value.maximumAmount) && typeof value.currencyCode === "string" && typeof value.chainId === "number" && typeof value.tokenContract === "string" && (value.usageType === "single_use" || value.usageType === "reusable") && typeof value.completedPayments === "number" && typeof value.startedCheckouts === "number" && isStringOrNull(value.activeAt) && isStringOrNull(value.expiresAt) && isStringOrNull(value.pausedAt) && isStringOrNull(value.archivedAt) && isPaymentLinkCollect(value.collect) && typeof value.referencePrefix === "string" && isStringOrNull(value.successUrl) && isStringOrNull(value.cancelUrl) && typeof value.successMessage === "string" && isMetadata(value.metadata) && isStringOrNull(value.reservationInvoiceId) && isStringOrNull(value.reservedAt) && typeof value.createdAt === "string" && typeof value.updatedAt === "string" && isStringOrNull(value.lastCheckoutCreatedAt);
706
+ var isPaymentLinkList = (value) => isRecord(value) && Array.isArray(value.items) && value.items.every(isPaymentLink) && typeof value.hasMore === "boolean" && isStringOrNull(value.nextCursor);
707
+ var isPaymentLinkPayments = (value) => isRecord(value) && Array.isArray(value.items) && value.items.every(isInvoice);
455
708
  var isPayment = (value) => {
456
709
  if (!isRecord(value)) {
457
710
  return false;
458
711
  }
459
- return typeof value.id === "string" && value.object === "payment" && typeof value.invoiceId === "string" && typeof value.invoiceNumber === "string" && isStringOrNull(value.transactionId) && typeof value.mode === "string" && typeof value.status === "string" && typeof value.amountExpected === "string" && typeof value.amountReceived === "string" && typeof value.platformFee === "string" && typeof value.netAmount === "string" && typeof value.chainId === "number" && typeof value.settlementWalletAddress === "string" && isStringOrNull(value.failureReason) && isStringOrNull(value.confirmedAt) && typeof value.createdAt === "string";
712
+ return typeof value.id === "string" && value.object === "payment" && typeof value.invoiceId === "string" && typeof value.invoiceNumber === "string" && isStringOrNull(value.transactionId) && typeof value.mode === "string" && typeof value.status === "string" && typeof value.amountExpected === "string" && typeof value.amountReceived === "string" && typeof value.customerAmountTendered === "string" && typeof value.customerAmountCredited === "string" && typeof value.expectedMerchantSettlement === "string" && typeof value.merchantAmountSettled === "string" && typeof value.platformFeeExpected === "string" && typeof value.platformFeeCollected === "string" && typeof value.payerWalletAddress === "string" && typeof value.payerWalletEvidence === "string" && typeof value.creditEvidenceType === "string" && typeof value.migrationState === "string" && typeof value.platformFee === "string" && typeof value.netAmount === "string" && typeof value.chainId === "number" && typeof value.settlementWalletAddress === "string" && isStringOrNull(value.failureReason) && isStringOrNull(value.confirmedAt) && typeof value.createdAt === "string";
460
713
  };
461
714
  var isWebhookEndpoint = (value) => {
462
715
  if (!isRecord(value)) {
463
716
  return false;
464
717
  }
465
- return typeof value.id === "string" && value.object === "webhook_endpoint" && typeof value.mode === "string" && typeof value.url === "string" && typeof value.enabled === "boolean" && isStringArray(value.eventTypes) && typeof value.signingSecret === "string" && typeof value.createdAt === "string";
718
+ return typeof value.id === "string" && value.object === "webhook_endpoint" && typeof value.mode === "string" && typeof value.url === "string" && typeof value.enabled === "boolean" && isStringArray(value.eventTypes) && (value.signingSecret === void 0 || typeof value.signingSecret === "string") && (value.copyRequired === void 0 || typeof value.copyRequired === "boolean") && typeof value.currentSecretVersion === "number" && Array.isArray(value.secretVersions) && value.secretVersions.every(isWebhookSecretVersion) && isRecord(value.secretOverlap) && typeof value.secretOverlap.status === "string" && isStringOrNull(value.secretOverlap.expiresAt) && (typeof value.secretOverlap.previousVersion === "number" || value.secretOverlap.previousVersion === null) && typeof value.createdAt === "string" && typeof value.updatedAt === "string";
466
719
  };
720
+ var isWebhookSecretVersion = (value) => isRecord(value) && typeof value.version === "number" && typeof value.createdAt === "string" && typeof value.activatesAt === "string" && isStringOrNull(value.expiresAt) && isStringOrNull(value.revokedAt) && isStringOrNull(value.testedAt);
721
+ var isWebhookEndpointArray = (value) => Array.isArray(value) && value.every(isWebhookEndpoint);
722
+ var isWebhookEndpointArchive = (value) => isRecord(value) && typeof value.id === "string" && value.object === "webhook_endpoint" && value.archived === true;
723
+ var isWebhookIncident = (value) => isRecord(value) && typeof value.id === "string" && value.object === "webhook_incident" && typeof value.endpointId === "string" && typeof value.mode === "string" && typeof value.status === "string" && typeof value.reasonFamily === "string" && typeof value.failureCount === "number" && typeof value.affectedDeliveryCount === "number" && isStringArray(value.affectedDeliveryIds) && typeof value.firstFailedAt === "string" && typeof value.lastFailedAt === "string" && typeof value.openedAt === "string" && isStringOrNull(value.resolvedAt) && typeof value.lastDeliveryId === "string" && typeof value.lastAttemptId === "string" && typeof value.createdAt === "string" && typeof value.updatedAt === "string";
724
+ var isWebhookIncidentArray = (value) => Array.isArray(value) && value.every(isWebhookIncident);
467
725
  var isWebhookEvent = (value) => {
468
726
  if (!isRecord(value)) {
469
727
  return false;
@@ -474,15 +732,22 @@ var isWebhookDeliveryAttemptSummary = (value) => {
474
732
  if (!isRecord(value)) {
475
733
  return false;
476
734
  }
477
- return (typeof value.responseStatusCode === "number" || value.responseStatusCode === null) && isStringOrNull(value.errorMessage) && typeof value.attemptedAt === "string";
735
+ return (typeof value.responseStatusCode === "number" || value.responseStatusCode === null) && isStringOrNull(value.errorMessage) && (value.errorCategory === void 0 || isStringOrNull(value.errorCategory)) && typeof value.attemptedAt === "string";
478
736
  };
737
+ var isWebhookDeliveryAttempt = (value) => isRecord(value) && typeof value.id === "string" && typeof value.attemptNumber === "number" && (typeof value.responseStatusCode === "number" || value.responseStatusCode === null) && isStringOrNull(value.responseBody) && typeof value.responseBodyTruncated === "boolean" && isStringOrNull(value.errorMessage) && (value.errorCategory === void 0 || isStringOrNull(value.errorCategory)) && (value.responseHeaders === void 0 || value.responseHeaders === null || isRecord(value.responseHeaders)) && (value.requestHeaders === void 0 || value.requestHeaders === null || isRecord(value.requestHeaders)) && (value.destinationHost === void 0 || typeof value.destinationHost === "string") && (value.sanitizedAt === void 0 || typeof value.sanitizedAt === "string") && typeof value.attemptedAt === "string" && typeof value.startedAt === "string" && typeof value.completedAt === "string" && typeof value.durationMs === "number";
479
738
  var isWebhookDelivery = (value) => {
480
739
  if (!isRecord(value)) {
481
740
  return false;
482
741
  }
483
- return typeof value.id === "string" && value.object === "webhook_delivery" && typeof value.endpointId === "string" && isStringOrNull(value.invoiceId) && typeof value.eventType === "string" && typeof value.status === "string" && typeof value.idempotencyKey === "string" && isWebhookEvent(value.payload) && typeof value.nextAttemptAt === "string" && isStringOrNull(value.deliveredAt) && typeof value.attemptCount === "number" && (value.latestAttempt === null || isWebhookDeliveryAttemptSummary(value.latestAttempt)) && typeof value.createdAt === "string";
742
+ return typeof value.id === "string" && value.object === "webhook_delivery" && typeof value.endpointId === "string" && isStringOrNull(value.invoiceId) && typeof value.eventId === "string" && typeof value.eventType === "string" && typeof value.status === "string" && typeof value.idempotencyKey === "string" && isWebhookEvent(value.payload) && typeof value.nextAttemptAt === "string" && isStringOrNull(value.deliveredAt) && typeof value.attemptCount === "number" && (value.latestErrorCategory === void 0 || isStringOrNull(value.latestErrorCategory)) && (value.latestAttempt === null || isWebhookDeliveryAttemptSummary(value.latestAttempt)) && isStringOrNull(value.replayOfDeliveryId) && isStringOrNull(value.replayRootDeliveryId) && isStringOrNull(value.replayedBy) && isStringOrNull(value.replayedAt) && typeof value.createdAt === "string";
484
743
  };
744
+ var isWebhookDeliveryDetail = (value) => isWebhookDelivery(value) && Array.isArray(value.attempts) && value.attempts.every(isWebhookDeliveryAttempt);
745
+ var isWebhookDeliveryAttemptArray = (value) => Array.isArray(value) && value.every(isWebhookDeliveryAttempt);
485
746
  var isWebhookDeliveryArray = (value) => Array.isArray(value) && value.every(isWebhookDelivery);
747
+ var isReconciliationSchema = (value) => isRecord(value) && typeof value.schemaVersion === "string" && Array.isArray(value.formats) && Array.isArray(value.dateBases) && typeof value.maximumRangeDays === "number" && typeof value.rangeEnd === "string" && typeof value.retention === "string" && Array.isArray(value.files) && Array.isArray(value.stateRules);
748
+ var isReconciliationSummary = (value) => isRecord(value) && typeof value.schemaVersion === "string" && typeof value.dateBasis === "string" && typeof value.from === "string" && typeof value.to === "string" && typeof value.cutoffAt === "string" && typeof value.timezone === "string" && isRecord(value.rowCounts) && Array.isArray(value.summaryByToken) && Array.isArray(value.exceptions) && isStringArray(value.warnings);
749
+ var isReconciliationExport = (value) => isRecord(value) && typeof value.id === "string" && typeof value.merchantId === "string" && typeof value.mode === "string" && typeof value.status === "string" && typeof value.format === "string" && typeof value.schemaVersion === "string" && isRecord(value.filters) && typeof value.filters.from === "string" && typeof value.filters.to === "string" && typeof value.dateBasis === "string" && typeof value.timezone === "string" && typeof value.requestedBy === "string" && typeof value.requestedAt === "string" && typeof value.attempts === "number" && typeof value.includePII === "boolean" && typeof value.createdAt === "string" && typeof value.updatedAt === "string";
750
+ var isReconciliationExportList = (value) => isRecord(value) && Array.isArray(value.items) && value.items.every(isReconciliationExport) && typeof value.hasMore === "boolean" && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
486
751
  var normalizePayloadBytes = (payload) => {
487
752
  if (typeof payload === "string") {
488
753
  return buffer.Buffer.from(payload, "utf8");
@@ -620,9 +885,10 @@ function assertPayclaveWebhookSignature({
620
885
  (candidate) => timingSafeHexEqual(candidate, expected)
621
886
  )) {
622
887
  throw new PayclaveError({
623
- message: "Payclave webhook signature is invalid.",
888
+ message: `Payclave webhook signature is invalid. Verify the signature against the exact raw request body before parsing it. See ${webhookRawBodyGuideUrl}`,
624
889
  code: "WEBHOOK_SIGNATURE_INVALID",
625
- status: 0
890
+ status: 0,
891
+ details: { documentationUrl: webhookRawBodyGuideUrl }
626
892
  });
627
893
  }
628
894
  }
@@ -660,7 +926,7 @@ function createPayclaveServerClient({
660
926
  secretKey,
661
927
  apiBaseUrl = defaultApiBaseUrl,
662
928
  fetcher = defaultFetcher,
663
- timeoutMs
929
+ timeoutMs = defaultTimeoutMs
664
930
  }) {
665
931
  assertSecretKey(secretKey);
666
932
  assertTimeoutMs(timeoutMs);
@@ -746,6 +1012,40 @@ function createPayclaveServerClient({
746
1012
  guard: isInvoice
747
1013
  });
748
1014
  };
1015
+ const createInvoiceDraft = (input) => {
1016
+ assertInvoiceDraftFields(input);
1017
+ const { signal, idempotencyKey, ...body } = input;
1018
+ return request({
1019
+ method: "POST",
1020
+ path: "/v1/invoices",
1021
+ body,
1022
+ idempotencyKey,
1023
+ signal,
1024
+ guard: isInvoice
1025
+ });
1026
+ };
1027
+ const listInvoices = (input = {}) => {
1028
+ const query = new URLSearchParams();
1029
+ if (input.limit !== void 0) {
1030
+ assertPositiveIntegerLimit(input.limit);
1031
+ query.set("limit", String(input.limit));
1032
+ }
1033
+ if (input.startingAfter !== void 0) {
1034
+ assertIdentifier(input.startingAfter, "Starting invoice id");
1035
+ query.set("startingAfter", input.startingAfter);
1036
+ }
1037
+ if (input.collectionState !== void 0) {
1038
+ assertIdentifier(input.collectionState, "Invoice collection state");
1039
+ query.set("collectionState", input.collectionState);
1040
+ }
1041
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
1042
+ return request({
1043
+ method: "GET",
1044
+ path: `/v1/invoices${suffix}`,
1045
+ signal: input.signal,
1046
+ guard: isInvoiceList
1047
+ });
1048
+ };
749
1049
  const getInvoice = (id, options = {}) => {
750
1050
  assertIdentifier(id, "Invoice id");
751
1051
  return request({
@@ -755,6 +1055,243 @@ function createPayclaveServerClient({
755
1055
  guard: isInvoice
756
1056
  });
757
1057
  };
1058
+ const downloadInvoicePDF = async (id, options = {}) => {
1059
+ assertIdentifier(id, "Invoice id");
1060
+ const response = await runFetch({
1061
+ fetcher,
1062
+ url: joinUrl(
1063
+ normalizedApiBaseUrl,
1064
+ `/v1/invoices/${encodePathSegment(id)}/pdf`
1065
+ ),
1066
+ init: {
1067
+ method: "GET",
1068
+ headers: {
1069
+ Accept: "application/pdf",
1070
+ Authorization: `Bearer ${secretKey}`,
1071
+ "X-Payclave-Client": buildClientHeader()
1072
+ }
1073
+ },
1074
+ externalSignal: options.signal,
1075
+ timeoutMs
1076
+ });
1077
+ return parseInvoicePDFResponse(response);
1078
+ };
1079
+ const updateInvoiceDraft = (id, input) => {
1080
+ assertIdentifier(id, "Invoice id");
1081
+ assertInvoiceDraftFields(input);
1082
+ assertInvoiceVersion(input.version);
1083
+ const { signal, idempotencyKey, ...body } = input;
1084
+ return request({
1085
+ method: "PATCH",
1086
+ path: `/v1/invoices/${encodePathSegment(id)}`,
1087
+ body,
1088
+ idempotencyKey,
1089
+ signal,
1090
+ guard: isInvoice
1091
+ });
1092
+ };
1093
+ const issueInvoice = (id, input) => {
1094
+ assertIdentifier(id, "Invoice id");
1095
+ assertInvoiceVersion(input.version);
1096
+ return request({
1097
+ method: "POST",
1098
+ path: `/v1/invoices/${encodePathSegment(id)}/issue`,
1099
+ body: { version: input.version, send: input.send },
1100
+ idempotencyKey: input.idempotencyKey,
1101
+ signal: input.signal,
1102
+ guard: isInvoice
1103
+ });
1104
+ };
1105
+ const createInvoiceCheckoutSession = (id, input = {}) => {
1106
+ assertIdentifier(id, "Invoice id");
1107
+ return request({
1108
+ method: "POST",
1109
+ path: `/v1/invoices/${encodePathSegment(id)}/checkout-sessions`,
1110
+ idempotencyKey: input.idempotencyKey,
1111
+ signal: input.signal,
1112
+ guard: isInvoiceCheckoutSessionCreated
1113
+ });
1114
+ };
1115
+ const sendInvoice = (id, input = {}) => {
1116
+ assertIdentifier(id, "Invoice id");
1117
+ return request({
1118
+ method: "POST",
1119
+ path: `/v1/invoices/${encodePathSegment(id)}/send`,
1120
+ idempotencyKey: input.idempotencyKey,
1121
+ signal: input.signal,
1122
+ guard: isInvoice
1123
+ });
1124
+ };
1125
+ const remindInvoice = (id, input = {}) => {
1126
+ assertIdentifier(id, "Invoice id");
1127
+ return request({
1128
+ method: "POST",
1129
+ path: `/v1/invoices/${encodePathSegment(id)}/remind`,
1130
+ idempotencyKey: input.idempotencyKey,
1131
+ signal: input.signal,
1132
+ guard: isInvoice
1133
+ });
1134
+ };
1135
+ const invoiceAction = (id, path, input) => {
1136
+ assertIdentifier(id, "Invoice id");
1137
+ return request({
1138
+ method: "POST",
1139
+ path: `/v1/invoices/${encodePathSegment(id)}/${path}`,
1140
+ body: compact({ reason: input.reason }),
1141
+ idempotencyKey: input.idempotencyKey,
1142
+ signal: input.signal,
1143
+ guard: isInvoice
1144
+ });
1145
+ };
1146
+ const voidInvoice = (id, input = {}) => invoiceAction(id, "void", input);
1147
+ const voidInvoiceRemaining = (id, input = {}) => invoiceAction(id, "void-remaining", input);
1148
+ const markInvoiceUncollectible = (id, input = {}) => invoiceAction(id, "mark-uncollectible", input);
1149
+ const duplicateInvoice = (id, input = {}) => {
1150
+ assertIdentifier(id, "Invoice id");
1151
+ return request({
1152
+ method: "POST",
1153
+ path: `/v1/invoices/${encodePathSegment(id)}/duplicate`,
1154
+ idempotencyKey: input.idempotencyKey,
1155
+ signal: input.signal,
1156
+ guard: isInvoice
1157
+ });
1158
+ };
1159
+ const recordInvoiceRefundReference = (id, input) => {
1160
+ assertIdentifier(id, "Invoice id");
1161
+ assertIdentifier(input.paymentId, "Payment id");
1162
+ assertAmount(input.amount);
1163
+ const { signal, idempotencyKey, ...body } = input;
1164
+ return request({
1165
+ method: "POST",
1166
+ path: `/v1/invoices/${encodePathSegment(id)}/refund-references`,
1167
+ body,
1168
+ idempotencyKey,
1169
+ signal,
1170
+ guard: isRefundReferenceResult
1171
+ });
1172
+ };
1173
+ const checkInvoiceRefund = (id, input) => {
1174
+ assertIdentifier(id, "Invoice id");
1175
+ assertIdentifier(input.paymentId, "Payment id");
1176
+ assertAmount(input.amount);
1177
+ const { signal, ...body } = input;
1178
+ return request({
1179
+ method: "POST",
1180
+ path: `/v1/invoices/${encodePathSegment(id)}/refund-checks`,
1181
+ body,
1182
+ signal,
1183
+ guard: isRefundDecision
1184
+ });
1185
+ };
1186
+ const createPaymentLink = (input) => {
1187
+ assertPaymentLinkFields(input);
1188
+ return request({
1189
+ method: "POST",
1190
+ path: "/v1/payment-links",
1191
+ body: paymentLinkBody(input),
1192
+ idempotencyKey: input.idempotencyKey,
1193
+ signal: input.signal,
1194
+ guard: isPaymentLink
1195
+ });
1196
+ };
1197
+ const listPaymentLinks = (input = {}) => {
1198
+ const query = new URLSearchParams();
1199
+ if (input.limit !== void 0) {
1200
+ assertPositiveIntegerLimit(input.limit);
1201
+ query.set("limit", String(input.limit));
1202
+ }
1203
+ for (const [name, value] of [
1204
+ ["startingAfter", input.startingAfter],
1205
+ ["status", input.status],
1206
+ ["amountType", input.amountType],
1207
+ ["usageType", input.usageType],
1208
+ ["currencyCode", input.currencyCode],
1209
+ ["search", input.search],
1210
+ ["createdFrom", input.createdFrom],
1211
+ ["createdTo", input.createdTo]
1212
+ ]) {
1213
+ if (value !== void 0) {
1214
+ assertIdentifier(value, name);
1215
+ query.set(name, value);
1216
+ }
1217
+ }
1218
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
1219
+ return request({
1220
+ method: "GET",
1221
+ path: `/v1/payment-links${suffix}`,
1222
+ signal: input.signal,
1223
+ guard: isPaymentLinkList
1224
+ });
1225
+ };
1226
+ const getPaymentLink = (id, options = {}) => {
1227
+ assertIdentifier(id, "Payment link id");
1228
+ return request({
1229
+ method: "GET",
1230
+ path: `/v1/payment-links/${encodePathSegment(id)}`,
1231
+ signal: options.signal,
1232
+ guard: isPaymentLink
1233
+ });
1234
+ };
1235
+ const updatePaymentLink = (id, input) => {
1236
+ assertIdentifier(id, "Payment link id");
1237
+ assertPaymentLinkFields(input);
1238
+ assertPaymentLinkVersion(input.version);
1239
+ return request({
1240
+ method: "PATCH",
1241
+ path: `/v1/payment-links/${encodePathSegment(id)}`,
1242
+ body: { ...paymentLinkBody(input), version: input.version },
1243
+ idempotencyKey: input.idempotencyKey,
1244
+ signal: input.signal,
1245
+ guard: isPaymentLink
1246
+ });
1247
+ };
1248
+ const paymentLinkAction = (id, action, input = {}) => {
1249
+ assertIdentifier(id, "Payment link id");
1250
+ return request({
1251
+ method: "POST",
1252
+ path: `/v1/payment-links/${encodePathSegment(id)}/${action}`,
1253
+ idempotencyKey: input.idempotencyKey,
1254
+ signal: input.signal,
1255
+ guard: isPaymentLink
1256
+ });
1257
+ };
1258
+ const pausePaymentLink = (id, input = {}) => paymentLinkAction(id, "pause", input);
1259
+ const resumePaymentLink = (id, input = {}) => paymentLinkAction(id, "resume", input);
1260
+ const archivePaymentLink = (id, input = {}) => paymentLinkAction(id, "archive", input);
1261
+ const duplicatePaymentLink = (id, input = {}) => paymentLinkAction(id, "duplicate", input);
1262
+ const releasePaymentLinkReservation = (id, input) => {
1263
+ assertIdentifier(id, "Payment link id");
1264
+ if (input.acknowledgeLatePaymentRisk !== true) {
1265
+ throw new PayclaveError({
1266
+ message: "Payment-link reservation release requires explicit late-payment risk acknowledgement.",
1267
+ code: "INVALID_REQUEST_BODY",
1268
+ status: 0
1269
+ });
1270
+ }
1271
+ return request({
1272
+ method: "POST",
1273
+ path: `/v1/payment-links/${encodePathSegment(id)}/release-reservation`,
1274
+ body: { acknowledgeLatePaymentRisk: input.acknowledgeLatePaymentRisk },
1275
+ idempotencyKey: input.idempotencyKey,
1276
+ signal: input.signal,
1277
+ guard: isPaymentLink
1278
+ });
1279
+ };
1280
+ const listPaymentLinkPayments = (id, input = {}) => {
1281
+ assertIdentifier(id, "Payment link id");
1282
+ const query = new URLSearchParams();
1283
+ if (input.limit !== void 0) {
1284
+ assertPositiveIntegerLimit(input.limit);
1285
+ query.set("limit", String(input.limit));
1286
+ }
1287
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
1288
+ return request({
1289
+ method: "GET",
1290
+ path: `/v1/payment-links/${encodePathSegment(id)}/payments${suffix}`,
1291
+ signal: input.signal,
1292
+ guard: isPaymentLinkPayments
1293
+ });
1294
+ };
758
1295
  const getPayment = (id, options = {}) => {
759
1296
  assertIdentifier(id, "Payment id");
760
1297
  return request({
@@ -778,6 +1315,75 @@ function createPayclaveServerClient({
778
1315
  guard: isWebhookEndpoint
779
1316
  });
780
1317
  };
1318
+ const listWebhookEndpoints = (options = {}) => request({
1319
+ method: "GET",
1320
+ path: "/v1/webhook-endpoints",
1321
+ signal: options.signal,
1322
+ guard: isWebhookEndpointArray
1323
+ });
1324
+ const getWebhookEndpoint = (id, options = {}) => {
1325
+ assertIdentifier(id, "Webhook endpoint id");
1326
+ return request({
1327
+ method: "GET",
1328
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}`,
1329
+ signal: options.signal,
1330
+ guard: isWebhookEndpoint
1331
+ });
1332
+ };
1333
+ const updateWebhookEndpoint = (id, input) => {
1334
+ assertIdentifier(id, "Webhook endpoint id");
1335
+ const url = input.url === void 0 ? void 0 : normalizeWebhookUrl(input.url);
1336
+ assertWebhookEventTypes(input.eventTypes);
1337
+ if (input.alertThreshold !== void 0 && (!Number.isInteger(input.alertThreshold) || input.alertThreshold < 2 || input.alertThreshold > 10)) {
1338
+ throw new PayclaveError({
1339
+ message: "Webhook alert threshold must be between 2 and 10.",
1340
+ code: "INVALID_ARGUMENT",
1341
+ status: 0
1342
+ });
1343
+ }
1344
+ const { signal, idempotencyKey, ...rest } = input;
1345
+ const body = { ...rest, ...url === void 0 ? {} : { url } };
1346
+ return request({
1347
+ method: "PATCH",
1348
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}`,
1349
+ body,
1350
+ idempotencyKey,
1351
+ signal,
1352
+ guard: isWebhookEndpoint
1353
+ });
1354
+ };
1355
+ const archiveWebhookEndpoint = (id, input) => {
1356
+ assertIdentifier(id, "Webhook endpoint id");
1357
+ return request({
1358
+ method: "DELETE",
1359
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}`,
1360
+ idempotencyKey: input.idempotencyKey,
1361
+ signal: input.signal,
1362
+ guard: isWebhookEndpointArchive
1363
+ });
1364
+ };
1365
+ const rotateWebhookSecret = (id, input) => {
1366
+ assertIdentifier(id, "Webhook endpoint id");
1367
+ return request({
1368
+ method: "POST",
1369
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}/rotate-secret`,
1370
+ body: {},
1371
+ idempotencyKey: input.idempotencyKey,
1372
+ signal: input.signal,
1373
+ guard: isWebhookEndpoint
1374
+ });
1375
+ };
1376
+ const endWebhookSecretOverlap = (id, input) => {
1377
+ assertIdentifier(id, "Webhook endpoint id");
1378
+ return request({
1379
+ method: "POST",
1380
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}/end-secret-overlap`,
1381
+ body: {},
1382
+ idempotencyKey: input.idempotencyKey,
1383
+ signal: input.signal,
1384
+ guard: isWebhookEndpoint
1385
+ });
1386
+ };
781
1387
  const createTestWebhook = (input) => {
782
1388
  assertIdentifier(input.endpointId, "Webhook endpoint id");
783
1389
  assertWebhookEventTypes(
@@ -799,7 +1405,23 @@ function createPayclaveServerClient({
799
1405
  if (limit !== void 0) {
800
1406
  assertPositiveIntegerLimit(limit);
801
1407
  }
802
- const query = limit !== void 0 ? `?limit=${encodeURIComponent(String(limit))}` : "";
1408
+ const params = new URLSearchParams();
1409
+ if (limit !== void 0) params.set("limit", String(limit));
1410
+ for (const [key, value] of [
1411
+ ["endpointId", input.endpointId],
1412
+ ["eventType", input.eventType],
1413
+ ["status", input.status],
1414
+ ["createdFrom", input.createdFrom],
1415
+ ["createdTo", input.createdTo],
1416
+ ["replayStatus", input.replayStatus],
1417
+ ["responseFamily", input.responseFamily]
1418
+ ]) {
1419
+ if (value !== void 0) {
1420
+ assertIdentifier(value, key);
1421
+ params.set(key, value);
1422
+ }
1423
+ }
1424
+ const query = params.size > 0 ? `?${params.toString()}` : "";
803
1425
  return request({
804
1426
  method: "GET",
805
1427
  path: `/v1/webhook-deliveries${query}`,
@@ -807,19 +1429,226 @@ function createPayclaveServerClient({
807
1429
  guard: isWebhookDeliveryArray
808
1430
  });
809
1431
  };
1432
+ const getWebhookDelivery = (id, options = {}) => {
1433
+ assertIdentifier(id, "Webhook delivery id");
1434
+ return request({
1435
+ method: "GET",
1436
+ path: `/v1/webhook-deliveries/${encodePathSegment(id)}`,
1437
+ signal: options.signal,
1438
+ guard: isWebhookDeliveryDetail
1439
+ });
1440
+ };
1441
+ const listWebhookDeliveryAttempts = (id, options = {}) => {
1442
+ assertIdentifier(id, "Webhook delivery id");
1443
+ return request({
1444
+ method: "GET",
1445
+ path: `/v1/webhook-deliveries/${encodePathSegment(id)}/attempts`,
1446
+ signal: options.signal,
1447
+ guard: isWebhookDeliveryAttemptArray
1448
+ });
1449
+ };
1450
+ const replayWebhookDelivery = (id, input) => {
1451
+ assertIdentifier(id, "Webhook delivery id");
1452
+ return request({
1453
+ method: "POST",
1454
+ path: `/v1/webhook-deliveries/${encodePathSegment(id)}/replay`,
1455
+ idempotencyKey: input.idempotencyKey,
1456
+ signal: input.signal,
1457
+ guard: isWebhookDeliveryDetail
1458
+ });
1459
+ };
1460
+ const listWebhookIncidents = (input = {}) => {
1461
+ const query = input.status ? `?status=${input.status}` : "";
1462
+ return request({
1463
+ method: "GET",
1464
+ path: `/v1/webhook-incidents${query}`,
1465
+ signal: input.signal,
1466
+ guard: isWebhookIncidentArray
1467
+ });
1468
+ };
1469
+ const getWebhookIncident = (id, options = {}) => {
1470
+ assertIdentifier(id, "Webhook incident id");
1471
+ return request({
1472
+ method: "GET",
1473
+ path: `/v1/webhook-incidents/${encodePathSegment(id)}`,
1474
+ signal: options.signal,
1475
+ guard: isWebhookIncident
1476
+ });
1477
+ };
1478
+ const getReconciliationSchema = (version = PAYCLAVE_RECONCILIATION_SCHEMA_VERSION, options = {}) => {
1479
+ assertIdentifier(version, "Reconciliation schema version");
1480
+ return request({
1481
+ method: "GET",
1482
+ path: `/v1/reconciliation/schema/${encodePathSegment(version)}`,
1483
+ signal: options.signal,
1484
+ guard: isReconciliationSchema
1485
+ });
1486
+ };
1487
+ const getReconciliationSummary = (input) => {
1488
+ assertIdentifier(input.dateBasis, "Reconciliation date basis");
1489
+ assertIdentifier(input.from, "Reconciliation from timestamp");
1490
+ assertIdentifier(input.to, "Reconciliation to timestamp");
1491
+ const query = new URLSearchParams({
1492
+ dateBasis: input.dateBasis,
1493
+ from: input.from,
1494
+ to: input.to,
1495
+ timezone: input.timezone ?? "UTC"
1496
+ });
1497
+ if (input.exceptionOnly !== void 0) {
1498
+ query.set("exceptionOnly", String(input.exceptionOnly));
1499
+ }
1500
+ for (const status of input.invoiceStatuses ?? []) {
1501
+ query.append("invoiceStatus", status);
1502
+ }
1503
+ for (const status of input.paymentStatuses ?? []) {
1504
+ query.append("paymentStatus", status);
1505
+ }
1506
+ for (const token of input.settlementTokens ?? []) {
1507
+ query.append("settlementToken", token);
1508
+ }
1509
+ return request({
1510
+ method: "GET",
1511
+ path: `/v1/reconciliation/summary?${query.toString()}`,
1512
+ signal: input.signal,
1513
+ guard: isReconciliationSummary
1514
+ });
1515
+ };
1516
+ const createReconciliationExport = (input) => {
1517
+ assertReconciliationFormat(input.format);
1518
+ assertIdentifier(input.dateBasis, "Reconciliation date basis");
1519
+ assertIdentifier(input.from, "Reconciliation from timestamp");
1520
+ assertIdentifier(input.to, "Reconciliation to timestamp");
1521
+ const { signal, idempotencyKey, ...fields } = input;
1522
+ return request({
1523
+ method: "POST",
1524
+ path: "/v1/reconciliation-exports",
1525
+ body: compact({
1526
+ ...fields,
1527
+ mode: input.mode ?? (secretKey.startsWith("sk_live_") ? "live" : "test"),
1528
+ timezone: input.timezone ?? "UTC",
1529
+ exceptionOnly: input.exceptionOnly ?? false,
1530
+ includePII: input.includePII ?? false,
1531
+ schemaVersion: input.schemaVersion ?? PAYCLAVE_RECONCILIATION_SCHEMA_VERSION
1532
+ }),
1533
+ idempotencyKey,
1534
+ signal,
1535
+ guard: isReconciliationExport
1536
+ });
1537
+ };
1538
+ const listReconciliationExports = (input = {}) => {
1539
+ const query = new URLSearchParams();
1540
+ if (input.limit !== void 0) {
1541
+ assertPositiveIntegerLimit(input.limit);
1542
+ query.set("limit", String(input.limit));
1543
+ }
1544
+ if (input.startingAfter !== void 0) {
1545
+ assertIdentifier(input.startingAfter, "Starting reconciliation export id");
1546
+ query.set("startingAfter", input.startingAfter);
1547
+ }
1548
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
1549
+ return request({
1550
+ method: "GET",
1551
+ path: `/v1/reconciliation-exports${suffix}`,
1552
+ signal: input.signal,
1553
+ guard: isReconciliationExportList
1554
+ });
1555
+ };
1556
+ const getReconciliationExport = (id, options = {}) => {
1557
+ assertIdentifier(id, "Reconciliation export id");
1558
+ return request({
1559
+ method: "GET",
1560
+ path: `/v1/reconciliation-exports/${encodePathSegment(id)}`,
1561
+ signal: options.signal,
1562
+ guard: isReconciliationExport
1563
+ });
1564
+ };
1565
+ const cancelReconciliationExport = (id, input = {}) => {
1566
+ assertIdentifier(id, "Reconciliation export id");
1567
+ return request({
1568
+ method: "POST",
1569
+ path: `/v1/reconciliation-exports/${encodePathSegment(id)}/cancel`,
1570
+ idempotencyKey: input.idempotencyKey,
1571
+ signal: input.signal,
1572
+ guard: isReconciliationExport
1573
+ });
1574
+ };
1575
+ const downloadReconciliationExport = async (id, options = {}) => {
1576
+ assertIdentifier(id, "Reconciliation export id");
1577
+ const response = await runFetch({
1578
+ fetcher,
1579
+ url: joinUrl(
1580
+ normalizedApiBaseUrl,
1581
+ `/v1/reconciliation-exports/${encodePathSegment(id)}/download`
1582
+ ),
1583
+ init: {
1584
+ method: "GET",
1585
+ headers: {
1586
+ Accept: "application/zip",
1587
+ Authorization: `Bearer ${secretKey}`,
1588
+ "X-Payclave-Client": buildClientHeader()
1589
+ }
1590
+ },
1591
+ externalSignal: options.signal,
1592
+ timeoutMs
1593
+ });
1594
+ return parseReconciliationDownloadResponse(response);
1595
+ };
810
1596
  return {
811
1597
  createCheckoutSession,
812
1598
  getCheckoutSession,
813
1599
  createInvoice,
1600
+ createInvoiceDraft,
1601
+ listInvoices,
814
1602
  getInvoice,
1603
+ downloadInvoicePDF,
1604
+ updateInvoiceDraft,
1605
+ issueInvoice,
1606
+ sendInvoice,
1607
+ remindInvoice,
1608
+ createInvoiceCheckoutSession,
1609
+ voidInvoice,
1610
+ voidInvoiceRemaining,
1611
+ markInvoiceUncollectible,
1612
+ duplicateInvoice,
1613
+ checkInvoiceRefund,
1614
+ recordInvoiceRefundReference,
1615
+ createPaymentLink,
1616
+ listPaymentLinks,
1617
+ getPaymentLink,
1618
+ updatePaymentLink,
1619
+ pausePaymentLink,
1620
+ resumePaymentLink,
1621
+ archivePaymentLink,
1622
+ duplicatePaymentLink,
1623
+ releasePaymentLinkReservation,
1624
+ listPaymentLinkPayments,
815
1625
  getPayment,
816
1626
  createWebhookEndpoint,
1627
+ listWebhookEndpoints,
1628
+ getWebhookEndpoint,
1629
+ updateWebhookEndpoint,
1630
+ archiveWebhookEndpoint,
1631
+ rotateWebhookSecret,
1632
+ endWebhookSecretOverlap,
817
1633
  createTestWebhook,
818
- listWebhookDeliveries
1634
+ listWebhookDeliveries,
1635
+ getWebhookDelivery,
1636
+ listWebhookDeliveryAttempts,
1637
+ replayWebhookDelivery,
1638
+ listWebhookIncidents,
1639
+ getWebhookIncident,
1640
+ getReconciliationSchema,
1641
+ getReconciliationSummary,
1642
+ createReconciliationExport,
1643
+ listReconciliationExports,
1644
+ getReconciliationExport,
1645
+ cancelReconciliationExport,
1646
+ downloadReconciliationExport
819
1647
  };
820
1648
  }
821
1649
 
822
1650
  exports.PAYCLAVE_API_ERROR_CODES = PAYCLAVE_API_ERROR_CODES;
1651
+ exports.PAYCLAVE_RECONCILIATION_SCHEMA_VERSION = PAYCLAVE_RECONCILIATION_SCHEMA_VERSION;
823
1652
  exports.PAYCLAVE_SERVER_SDK_ERROR_CODES = PAYCLAVE_SERVER_SDK_ERROR_CODES;
824
1653
  exports.PAYCLAVE_SERVER_SDK_NAME = PAYCLAVE_SERVER_SDK_NAME;
825
1654
  exports.PAYCLAVE_SERVER_SDK_VERSION = PAYCLAVE_SERVER_SDK_VERSION;