@payclave/sdk-server 0.1.0 → 0.2.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,44 +5,123 @@ 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.payment_received_after_void",
17
+ "invoice.payment_received_after_uncollectible",
9
18
  "invoice.expired",
19
+ "payment_link.completed",
20
+ "payment_link.expired",
10
21
  "payment.failed",
11
22
  "payment.underpaid",
12
23
  "payment.overpaid"
13
24
  ];
25
+ var PAYCLAVE_RECONCILIATION_SCHEMA_VERSION = "2026-08-29.v1";
14
26
  var PAYCLAVE_API_ERROR_CODES = [
27
+ "ACCOUNT_SUSPENDED",
28
+ "ACTIVE_MERCHANT_REQUIRED",
15
29
  "API_KEY_FORBIDDEN",
16
30
  "API_KEY_REQUIRED",
17
31
  "AUTH_FORBIDDEN",
32
+ "GOOGLE_ACCOUNT_CONFLICT",
33
+ "GOOGLE_AUTH_CANCELLED",
34
+ "GOOGLE_AUTH_CODE_MISSING",
35
+ "GOOGLE_EMAIL_UNVERIFIED",
36
+ "GOOGLE_AUTH_EXCHANGE_FAILED",
37
+ "GOOGLE_AUTH_FAILED",
38
+ "GOOGLE_PROFILE_UNAVAILABLE",
39
+ "GOOGLE_AUTH_STATE_INVALID",
40
+ "AUTH_PASSWORD_ALREADY_SET",
41
+ "AUTH_PROXY_UNAUTHORIZED",
42
+ "AUTH_PROVIDER_UNAVAILABLE",
18
43
  "AUTH_REQUIRED",
44
+ "USE_SOCIAL_LOGIN",
45
+ "AUTH_VERIFIED_EMAIL_REQUIRED",
19
46
  "DEFAULT_WALLET_REQUIRED",
20
47
  "INTERNAL_JOB_UNAUTHORIZED",
21
48
  "INTERNAL_SERVER_ERROR",
22
49
  "INVALID_AMOUNT",
23
50
  "INVALID_API_KEY",
51
+ "INVALID_CREDENTIALS",
24
52
  "INVALID_EXPIRY",
25
53
  "INVALID_IDEMPOTENCY_KEY",
26
54
  "INVALID_DEPOSIT_NETWORK",
27
55
  "INVALID_WALLET_PAYMENT_ATTEMPT",
28
56
  "INVALID_TX_HASH",
29
57
  "INVALID_WALLET_ADDRESS",
58
+ "MODE_MISMATCH",
59
+ "MEMBERSHIP_REVOKED",
60
+ "MEMBER_ALREADY_EXISTS",
61
+ "MEMBER_LIMIT_REACHED",
62
+ "LAST_OWNER_REQUIRED",
63
+ "INVITATION_ALREADY_PENDING",
64
+ "INVITATION_ALREADY_USED",
65
+ "INVITATION_EMAIL_MISMATCH",
66
+ "INVITATION_EXPIRED",
67
+ "INVITATION_NOT_FOUND",
68
+ "OWNERSHIP_TRANSFER_REQUIRED",
30
69
  "NOT_FOUND",
70
+ "PUBLIC_KEY_FIELD_NOT_ALLOWED",
71
+ "PERMISSION_DENIED",
31
72
  "RATE_LIMIT_EXCEEDED",
73
+ "REAUTH_REQUIRED",
74
+ "STEP_UP_REQUIRED",
32
75
  "REQUEST_ERROR",
76
+ "REQUEST_TOO_LARGE",
33
77
  "SCAN_OR_COPY_UNAVAILABLE",
34
78
  "WALLET_PAYMENTS_UNAVAILABLE",
35
79
  "UNSUPPORTED_DEFAULT_WALLET",
36
80
  "VALIDATION_ERROR",
37
81
  "WEBHOOK_DELIVERY_NOT_FOUND",
82
+ "WEBHOOK_ENDPOINT_DISABLED",
38
83
  "WEBHOOK_ENDPOINT_NOT_FOUND",
39
84
  "WEBHOOK_EVENT_UNSUPPORTED",
85
+ "WEBHOOK_INCIDENT_NOT_FOUND",
40
86
  "WEBHOOK_SIGNATURE_INVALID",
87
+ "SECRET_OVERLAP_ACTIVE",
88
+ "SECRET_OVERLAP_EXPIRED",
41
89
  "CHECKOUT_SESSION_NOT_PAYABLE",
90
+ "EVENT_TYPE_UNSUPPORTED",
91
+ "EVENT_PAYLOAD_TOO_LARGE",
92
+ "JOURNEY_TOKEN_INVALID",
93
+ "EVENT_DUPLICATE",
94
+ "TIMESTAMP_OUT_OF_RANGE",
42
95
  "INVOICE_NOT_FOUND",
43
96
  "INVOICE_STATE_MISMATCH",
44
97
  "INVOICE_TRANSITION_GUARD_FAILED",
45
- "IDEMPOTENCY_KEY_CONFLICT"
98
+ "INVOICE_NOT_EDITABLE",
99
+ "INVOICE_ALREADY_ISSUED",
100
+ "INVOICE_NOT_PAYABLE",
101
+ "INVOICE_PDF_UNAVAILABLE",
102
+ "INVOICE_VERSION_CONFLICT",
103
+ "CURRENCY_MISMATCH",
104
+ "INVALID_TOTAL",
105
+ "CUSTOMER_EMAIL_REQUIRED",
106
+ "IDEMPOTENCY_KEY_CONFLICT",
107
+ "PAYMENT_LINK_NOT_FOUND",
108
+ "PAYMENT_LINK_VERSION_CONFLICT",
109
+ "LINK_INACTIVE",
110
+ "LINK_EXPIRED",
111
+ "LINK_ALREADY_USED",
112
+ "LINK_RESERVED",
113
+ "AMOUNT_OUT_OF_RANGE",
114
+ "FIELD_REQUIRED",
115
+ "FEATURE_UNAVAILABLE",
116
+ "MODE_UNAVAILABLE",
117
+ "CONFIG_CHANGED",
118
+ "RATE_LIMITED",
119
+ "EXPORT_RANGE_TOO_LARGE",
120
+ "EXPORT_NOT_READY",
121
+ "EXPORT_EXPIRED",
122
+ "EXPORT_CANCELLED",
123
+ "EXPORT_SCHEMA_UNSUPPORTED",
124
+ "EXPORT_TOO_LARGE_FOR_SYNC"
46
125
  ];
47
126
  var PAYCLAVE_SERVER_SDK_ERROR_CODES = [
48
127
  "INVALID_SECRET_KEY",
@@ -101,13 +180,15 @@ var PayclaveError = class extends Error {
101
180
  }
102
181
  };
103
182
  var PAYCLAVE_SERVER_SDK_NAME = "payclave-sdk-server";
104
- var PAYCLAVE_SERVER_SDK_VERSION = "0.1.0";
183
+ var PAYCLAVE_SERVER_SDK_VERSION = "0.2.0";
105
184
  var defaultApiBaseUrl = "https://api.payclave.com";
106
185
  var defaultFetcher = (input, init) => fetch(input, init);
107
186
  var secretKeyPattern = /^sk_(test|live)_[A-Za-z0-9_-]+$/;
108
187
  var amountPattern = /^(0|[1-9]\d*)(\.\d{1,6})?$/;
109
188
  var webhookUrlMessage = "Webhook URL must be a valid http or https URL.";
189
+ var webhookRawBodyGuideUrl = "https://www.payclave.com/developers/docs#webhooks";
110
190
  var defaultWebhookToleranceSeconds = 300;
191
+ var defaultTimeoutMs = 3e4;
111
192
  var minExpiryMinutes = 5;
112
193
  var maxExpiryMinutes = 24 * 60;
113
194
  var supportedWebhookEventTypes = new Set(PAYCLAVE_WEBHOOK_EVENT_TYPES);
@@ -120,6 +201,8 @@ var isPlainObject = (value) => {
120
201
  return prototype === Object.prototype || prototype === null;
121
202
  };
122
203
  var isStringOrNull = (value) => typeof value === "string" || value === null;
204
+ var isOptionalString = (value) => value === void 0 || typeof value === "string";
205
+ var isOptionalStringOrNull = (value) => value === void 0 || isStringOrNull(value);
123
206
  var isMetadata = (value) => isPlainObject(value);
124
207
  var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
125
208
  var joinUrl = (baseUrl, path) => `${baseUrl.replace(/\/+$/, "")}${path}`;
@@ -214,6 +297,79 @@ var assertOptionalMetadata = (metadata) => {
214
297
  });
215
298
  }
216
299
  };
300
+ var assertInvoiceDraftFields = (input) => {
301
+ if (!isPlainObject(input.customer) || !Array.isArray(input.lines) || input.lines.length < 1 || input.lines.length > 100) {
302
+ throw new PayclaveError({
303
+ message: "Invoice drafts require a customer object and 1 to 100 lines.",
304
+ code: "INVALID_REQUEST_BODY",
305
+ status: 0
306
+ });
307
+ }
308
+ assertOptionalMetadata(input.metadata);
309
+ assertOptionalExpiry(input.checkoutExpiresInMinutes);
310
+ };
311
+ var assertInvoiceVersion = (version) => {
312
+ if (typeof version !== "number" || !Number.isInteger(version) || version < 1) {
313
+ throw new PayclaveError({
314
+ message: "Invoice version must be a positive integer.",
315
+ code: "INVALID_REQUEST_BODY",
316
+ status: 0
317
+ });
318
+ }
319
+ };
320
+ var assertPaymentLinkFields = (input) => {
321
+ 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") {
322
+ throw new PayclaveError({
323
+ message: "Payment link fields are invalid.",
324
+ code: "INVALID_REQUEST_BODY",
325
+ status: 0
326
+ });
327
+ }
328
+ if (input.amountType === "fixed") {
329
+ assertAmount(input.amount);
330
+ } else {
331
+ assertAmount(input.minimumAmount);
332
+ if (input.maximumAmount !== void 0 && input.maximumAmount !== "") {
333
+ assertAmount(input.maximumAmount);
334
+ }
335
+ }
336
+ if (input.collect !== void 0 && (!isPlainObject(input.collect) || Object.values(input.collect).some((value) => typeof value !== "boolean"))) {
337
+ throw new PayclaveError({
338
+ message: "Payment link customer fields must be booleans.",
339
+ code: "INVALID_REQUEST_BODY",
340
+ status: 0
341
+ });
342
+ }
343
+ assertOptionalMetadata(input.metadata);
344
+ };
345
+ var assertPaymentLinkVersion = (version) => {
346
+ if (typeof version !== "number" || !Number.isInteger(version) || version < 1) {
347
+ throw new PayclaveError({
348
+ message: "Payment link version must be a positive integer.",
349
+ code: "INVALID_REQUEST_BODY",
350
+ status: 0
351
+ });
352
+ }
353
+ };
354
+ var paymentLinkBody = (input) => compact({
355
+ mode: input.mode,
356
+ title: input.title,
357
+ description: input.description,
358
+ amountType: input.amountType,
359
+ amount: input.amount,
360
+ minimumAmount: input.minimumAmount,
361
+ maximumAmount: input.maximumAmount,
362
+ currencyCode: input.currencyCode,
363
+ usageType: input.usageType,
364
+ activeAt: input.activeAt,
365
+ expiresAt: input.expiresAt,
366
+ collect: input.collect,
367
+ referencePrefix: input.referencePrefix,
368
+ successUrl: input.successUrl,
369
+ cancelUrl: input.cancelUrl,
370
+ successMessage: input.successMessage,
371
+ metadata: input.metadata
372
+ });
217
373
  var assertIdempotencyKey = (key) => {
218
374
  if (typeof key !== "string" || key.length === 0) {
219
375
  throw new PayclaveError({
@@ -299,6 +455,15 @@ var assertPositiveIntegerLimit = (limit) => {
299
455
  });
300
456
  }
301
457
  };
458
+ var assertReconciliationFormat = (format) => {
459
+ if (format !== "csv" && format !== "json") {
460
+ throw new PayclaveError({
461
+ message: "Reconciliation export format must be csv or json.",
462
+ code: "INVALID_REQUEST_BODY",
463
+ status: 0
464
+ });
465
+ }
466
+ };
302
467
  var serializeBody = (body) => {
303
468
  try {
304
469
  return JSON.stringify(body);
@@ -351,6 +516,98 @@ var parseResponse = async (response, guard) => {
351
516
  }
352
517
  return body.data;
353
518
  };
519
+ var parseInvoicePDFResponse = async (response) => {
520
+ const fallbackRequestId = response.headers.get("X-Request-ID");
521
+ if (!response.ok) {
522
+ const body = await response.json().catch(() => null);
523
+ if (isFailureResponse(body)) {
524
+ throw new PayclaveError({
525
+ message: body.error.message,
526
+ code: body.error.code,
527
+ status: response.status,
528
+ requestId: body.meta?.requestId ?? fallbackRequestId,
529
+ details: body.error.details
530
+ });
531
+ }
532
+ throw new PayclaveError({
533
+ message: "Payclave returned an invalid response.",
534
+ code: "INVALID_RESPONSE",
535
+ status: response.status,
536
+ requestId: fallbackRequestId
537
+ });
538
+ }
539
+ if (response.headers.get("content-type")?.split(";", 1)[0].trim() !== "application/pdf") {
540
+ throw new PayclaveError({
541
+ message: "Payclave returned an invalid invoice PDF response.",
542
+ code: "INVALID_RESPONSE",
543
+ status: response.status,
544
+ requestId: fallbackRequestId
545
+ });
546
+ }
547
+ const bytes = new Uint8Array(await response.arrayBuffer());
548
+ if (bytes.length < 5 || String.fromCharCode(...bytes.slice(0, 5)) !== "%PDF-") {
549
+ throw new PayclaveError({
550
+ message: "Payclave returned invalid invoice PDF bytes.",
551
+ code: "INVALID_RESPONSE",
552
+ status: response.status,
553
+ requestId: fallbackRequestId
554
+ });
555
+ }
556
+ const disposition = response.headers.get("content-disposition") ?? "";
557
+ const filenameMatch = disposition.match(
558
+ /filename=(?:"([^"\r\n/\\]+\.pdf)"|([^;\s\r\n/\\]+\.pdf))/i
559
+ );
560
+ const filename = filenameMatch?.[1] ?? filenameMatch?.[2] ?? "payclave-invoice.pdf";
561
+ return {
562
+ bytes,
563
+ contentType: "application/pdf",
564
+ filename,
565
+ requestId: fallbackRequestId
566
+ };
567
+ };
568
+ var parseReconciliationDownloadResponse = async (response) => {
569
+ const requestId = response.headers.get("X-Request-ID");
570
+ if (!response.ok) {
571
+ const body = await response.json().catch(() => null);
572
+ if (isFailureResponse(body)) {
573
+ throw new PayclaveError({
574
+ message: body.error.message,
575
+ code: body.error.code,
576
+ status: response.status,
577
+ requestId: body.meta?.requestId ?? requestId,
578
+ details: body.error.details
579
+ });
580
+ }
581
+ throw new PayclaveError({
582
+ message: "Payclave returned an invalid response.",
583
+ code: "INVALID_RESPONSE",
584
+ status: response.status,
585
+ requestId
586
+ });
587
+ }
588
+ if (response.headers.get("content-type")?.split(";", 1)[0].trim() !== "application/zip" || !response.body) {
589
+ throw new PayclaveError({
590
+ message: "Payclave returned an invalid reconciliation archive response.",
591
+ code: "INVALID_RESPONSE",
592
+ status: response.status,
593
+ requestId
594
+ });
595
+ }
596
+ const disposition = response.headers.get("content-disposition") ?? "";
597
+ const filenameMatch = disposition.match(
598
+ /filename=(?:"([^"\r\n/\\]+\.zip)"|([^;\s\r\n/\\]+\.zip))/i
599
+ );
600
+ const rawSize = response.headers.get("content-length");
601
+ const parsedSize = rawSize === null ? Number.NaN : Number(rawSize);
602
+ return {
603
+ stream: response.body,
604
+ contentType: "application/zip",
605
+ filename: filenameMatch?.[1] ?? filenameMatch?.[2] ?? "payclave-reconciliation.zip",
606
+ byteSize: Number.isSafeInteger(parsedSize) && parsedSize >= 0 ? parsedSize : null,
607
+ sha256: response.headers.get("X-Payclave-Content-SHA256"),
608
+ requestId
609
+ };
610
+ };
354
611
  var runFetch = async ({
355
612
  fetcher,
356
613
  url,
@@ -424,32 +681,44 @@ var isCreatedCheckoutSession = (value) => {
424
681
  if (!isRecord(value)) {
425
682
  return false;
426
683
  }
427
- 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.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";
684
+ 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";
428
685
  };
429
686
  var isCheckoutSession = (value) => {
430
687
  if (!isRecord(value)) {
431
688
  return false;
432
689
  }
433
- 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) && isStringOrNull(value.externalReference) && isStringOrNull(value.customerEmail) && isMetadata(value.metadata) && typeof value.checkoutUrl === "string" && typeof value.expiresAt === "string" && isStringOrNull(value.completedAt) && typeof value.createdAt === "string";
690
+ 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";
434
691
  };
435
692
  var isInvoice = (value) => {
436
693
  if (!isRecord(value)) {
437
694
  return false;
438
695
  }
439
- 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.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";
696
+ 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);
440
697
  };
698
+ 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";
699
+ var isRefundReferenceResult = (value) => isRecord(value) && isRecord(value.adjustment) && isInvoice(value.invoice);
700
+ var isInvoiceList = (value) => isRecord(value) && Array.isArray(value.items) && value.items.every(isInvoice) && typeof value.hasMore === "boolean" && isStringOrNull(value.nextCursor);
701
+ var isPaymentLinkCollect = (value) => isRecord(value) && typeof value.email === "boolean" && typeof value.name === "boolean" && typeof value.reference === "boolean";
702
+ 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);
703
+ var isPaymentLinkList = (value) => isRecord(value) && Array.isArray(value.items) && value.items.every(isPaymentLink) && typeof value.hasMore === "boolean" && isStringOrNull(value.nextCursor);
704
+ var isPaymentLinkPayments = (value) => isRecord(value) && Array.isArray(value.items) && value.items.every(isInvoice);
441
705
  var isPayment = (value) => {
442
706
  if (!isRecord(value)) {
443
707
  return false;
444
708
  }
445
- 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.chainId === "number" && typeof value.settlementWalletAddress === "string" && isStringOrNull(value.failureReason) && isStringOrNull(value.confirmedAt) && typeof value.createdAt === "string";
709
+ 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";
446
710
  };
447
711
  var isWebhookEndpoint = (value) => {
448
712
  if (!isRecord(value)) {
449
713
  return false;
450
714
  }
451
- 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";
715
+ 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";
452
716
  };
717
+ 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);
718
+ var isWebhookEndpointArray = (value) => Array.isArray(value) && value.every(isWebhookEndpoint);
719
+ var isWebhookEndpointArchive = (value) => isRecord(value) && typeof value.id === "string" && value.object === "webhook_endpoint" && value.archived === true;
720
+ 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";
721
+ var isWebhookIncidentArray = (value) => Array.isArray(value) && value.every(isWebhookIncident);
453
722
  var isWebhookEvent = (value) => {
454
723
  if (!isRecord(value)) {
455
724
  return false;
@@ -460,15 +729,22 @@ var isWebhookDeliveryAttemptSummary = (value) => {
460
729
  if (!isRecord(value)) {
461
730
  return false;
462
731
  }
463
- return (typeof value.responseStatusCode === "number" || value.responseStatusCode === null) && isStringOrNull(value.errorMessage) && typeof value.attemptedAt === "string";
732
+ return (typeof value.responseStatusCode === "number" || value.responseStatusCode === null) && isStringOrNull(value.errorMessage) && (value.errorCategory === void 0 || isStringOrNull(value.errorCategory)) && typeof value.attemptedAt === "string";
464
733
  };
734
+ 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";
465
735
  var isWebhookDelivery = (value) => {
466
736
  if (!isRecord(value)) {
467
737
  return false;
468
738
  }
469
- 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";
739
+ 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";
470
740
  };
741
+ var isWebhookDeliveryDetail = (value) => isWebhookDelivery(value) && Array.isArray(value.attempts) && value.attempts.every(isWebhookDeliveryAttempt);
742
+ var isWebhookDeliveryAttemptArray = (value) => Array.isArray(value) && value.every(isWebhookDeliveryAttempt);
471
743
  var isWebhookDeliveryArray = (value) => Array.isArray(value) && value.every(isWebhookDelivery);
744
+ 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);
745
+ 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);
746
+ 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";
747
+ 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");
472
748
  var normalizePayloadBytes = (payload) => {
473
749
  if (typeof payload === "string") {
474
750
  return buffer.Buffer.from(payload, "utf8");
@@ -597,14 +873,19 @@ function assertPayclaveWebhookSignature({
597
873
  status: 0
598
874
  });
599
875
  }
600
- const expected = expectedWebhookSignature(payload, trimmedSecret, parsed.timestamp);
876
+ const expected = expectedWebhookSignature(
877
+ payload,
878
+ trimmedSecret,
879
+ parsed.timestamp
880
+ );
601
881
  if (!parsed.signatures.some(
602
882
  (candidate) => timingSafeHexEqual(candidate, expected)
603
883
  )) {
604
884
  throw new PayclaveError({
605
- message: "Payclave webhook signature is invalid.",
885
+ message: `Payclave webhook signature is invalid. Verify the signature against the exact raw request body before parsing it. See ${webhookRawBodyGuideUrl}`,
606
886
  code: "WEBHOOK_SIGNATURE_INVALID",
607
- status: 0
887
+ status: 0,
888
+ details: { documentationUrl: webhookRawBodyGuideUrl }
608
889
  });
609
890
  }
610
891
  }
@@ -642,7 +923,7 @@ function createPayclaveServerClient({
642
923
  secretKey,
643
924
  apiBaseUrl = defaultApiBaseUrl,
644
925
  fetcher = defaultFetcher,
645
- timeoutMs
926
+ timeoutMs = defaultTimeoutMs
646
927
  }) {
647
928
  assertSecretKey(secretKey);
648
929
  assertTimeoutMs(timeoutMs);
@@ -728,6 +1009,40 @@ function createPayclaveServerClient({
728
1009
  guard: isInvoice
729
1010
  });
730
1011
  };
1012
+ const createInvoiceDraft = (input) => {
1013
+ assertInvoiceDraftFields(input);
1014
+ const { signal, idempotencyKey, ...body } = input;
1015
+ return request({
1016
+ method: "POST",
1017
+ path: "/v1/invoices",
1018
+ body,
1019
+ idempotencyKey,
1020
+ signal,
1021
+ guard: isInvoice
1022
+ });
1023
+ };
1024
+ const listInvoices = (input = {}) => {
1025
+ const query = new URLSearchParams();
1026
+ if (input.limit !== void 0) {
1027
+ assertPositiveIntegerLimit(input.limit);
1028
+ query.set("limit", String(input.limit));
1029
+ }
1030
+ if (input.startingAfter !== void 0) {
1031
+ assertIdentifier(input.startingAfter, "Starting invoice id");
1032
+ query.set("startingAfter", input.startingAfter);
1033
+ }
1034
+ if (input.collectionState !== void 0) {
1035
+ assertIdentifier(input.collectionState, "Invoice collection state");
1036
+ query.set("collectionState", input.collectionState);
1037
+ }
1038
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
1039
+ return request({
1040
+ method: "GET",
1041
+ path: `/v1/invoices${suffix}`,
1042
+ signal: input.signal,
1043
+ guard: isInvoiceList
1044
+ });
1045
+ };
731
1046
  const getInvoice = (id, options = {}) => {
732
1047
  assertIdentifier(id, "Invoice id");
733
1048
  return request({
@@ -737,6 +1052,230 @@ function createPayclaveServerClient({
737
1052
  guard: isInvoice
738
1053
  });
739
1054
  };
1055
+ const downloadInvoicePDF = async (id, options = {}) => {
1056
+ assertIdentifier(id, "Invoice id");
1057
+ const response = await runFetch({
1058
+ fetcher,
1059
+ url: joinUrl(
1060
+ normalizedApiBaseUrl,
1061
+ `/v1/invoices/${encodePathSegment(id)}/pdf`
1062
+ ),
1063
+ init: {
1064
+ method: "GET",
1065
+ headers: {
1066
+ Accept: "application/pdf",
1067
+ Authorization: `Bearer ${secretKey}`,
1068
+ "X-Payclave-Client": buildClientHeader()
1069
+ }
1070
+ },
1071
+ externalSignal: options.signal,
1072
+ timeoutMs
1073
+ });
1074
+ return parseInvoicePDFResponse(response);
1075
+ };
1076
+ const updateInvoiceDraft = (id, input) => {
1077
+ assertIdentifier(id, "Invoice id");
1078
+ assertInvoiceDraftFields(input);
1079
+ assertInvoiceVersion(input.version);
1080
+ const { signal, idempotencyKey, ...body } = input;
1081
+ return request({
1082
+ method: "PATCH",
1083
+ path: `/v1/invoices/${encodePathSegment(id)}`,
1084
+ body,
1085
+ idempotencyKey,
1086
+ signal,
1087
+ guard: isInvoice
1088
+ });
1089
+ };
1090
+ const issueInvoice = (id, input) => {
1091
+ assertIdentifier(id, "Invoice id");
1092
+ assertInvoiceVersion(input.version);
1093
+ return request({
1094
+ method: "POST",
1095
+ path: `/v1/invoices/${encodePathSegment(id)}/issue`,
1096
+ body: { version: input.version, send: input.send },
1097
+ idempotencyKey: input.idempotencyKey,
1098
+ signal: input.signal,
1099
+ guard: isInvoice
1100
+ });
1101
+ };
1102
+ const createInvoiceCheckoutSession = (id, input = {}) => {
1103
+ assertIdentifier(id, "Invoice id");
1104
+ return request({
1105
+ method: "POST",
1106
+ path: `/v1/invoices/${encodePathSegment(id)}/checkout-sessions`,
1107
+ idempotencyKey: input.idempotencyKey,
1108
+ signal: input.signal,
1109
+ guard: isInvoiceCheckoutSessionCreated
1110
+ });
1111
+ };
1112
+ const sendInvoice = (id, input = {}) => {
1113
+ assertIdentifier(id, "Invoice id");
1114
+ return request({
1115
+ method: "POST",
1116
+ path: `/v1/invoices/${encodePathSegment(id)}/send`,
1117
+ idempotencyKey: input.idempotencyKey,
1118
+ signal: input.signal,
1119
+ guard: isInvoice
1120
+ });
1121
+ };
1122
+ const remindInvoice = (id, input = {}) => {
1123
+ assertIdentifier(id, "Invoice id");
1124
+ return request({
1125
+ method: "POST",
1126
+ path: `/v1/invoices/${encodePathSegment(id)}/remind`,
1127
+ idempotencyKey: input.idempotencyKey,
1128
+ signal: input.signal,
1129
+ guard: isInvoice
1130
+ });
1131
+ };
1132
+ const invoiceAction = (id, path, input) => {
1133
+ assertIdentifier(id, "Invoice id");
1134
+ return request({
1135
+ method: "POST",
1136
+ path: `/v1/invoices/${encodePathSegment(id)}/${path}`,
1137
+ body: compact({ reason: input.reason }),
1138
+ idempotencyKey: input.idempotencyKey,
1139
+ signal: input.signal,
1140
+ guard: isInvoice
1141
+ });
1142
+ };
1143
+ const voidInvoice = (id, input = {}) => invoiceAction(id, "void", input);
1144
+ const voidInvoiceRemaining = (id, input = {}) => invoiceAction(id, "void-remaining", input);
1145
+ const markInvoiceUncollectible = (id, input = {}) => invoiceAction(id, "mark-uncollectible", input);
1146
+ const duplicateInvoice = (id, input = {}) => {
1147
+ assertIdentifier(id, "Invoice id");
1148
+ return request({
1149
+ method: "POST",
1150
+ path: `/v1/invoices/${encodePathSegment(id)}/duplicate`,
1151
+ idempotencyKey: input.idempotencyKey,
1152
+ signal: input.signal,
1153
+ guard: isInvoice
1154
+ });
1155
+ };
1156
+ const recordInvoiceRefundReference = (id, input) => {
1157
+ assertIdentifier(id, "Invoice id");
1158
+ assertIdentifier(input.paymentId, "Payment id");
1159
+ assertAmount(input.amount);
1160
+ const { signal, idempotencyKey, ...body } = input;
1161
+ return request({
1162
+ method: "POST",
1163
+ path: `/v1/invoices/${encodePathSegment(id)}/refund-references`,
1164
+ body,
1165
+ idempotencyKey,
1166
+ signal,
1167
+ guard: isRefundReferenceResult
1168
+ });
1169
+ };
1170
+ const createPaymentLink = (input) => {
1171
+ assertPaymentLinkFields(input);
1172
+ return request({
1173
+ method: "POST",
1174
+ path: "/v1/payment-links",
1175
+ body: paymentLinkBody(input),
1176
+ idempotencyKey: input.idempotencyKey,
1177
+ signal: input.signal,
1178
+ guard: isPaymentLink
1179
+ });
1180
+ };
1181
+ const listPaymentLinks = (input = {}) => {
1182
+ const query = new URLSearchParams();
1183
+ if (input.limit !== void 0) {
1184
+ assertPositiveIntegerLimit(input.limit);
1185
+ query.set("limit", String(input.limit));
1186
+ }
1187
+ for (const [name, value] of [
1188
+ ["startingAfter", input.startingAfter],
1189
+ ["status", input.status],
1190
+ ["amountType", input.amountType],
1191
+ ["usageType", input.usageType],
1192
+ ["currencyCode", input.currencyCode],
1193
+ ["search", input.search],
1194
+ ["createdFrom", input.createdFrom],
1195
+ ["createdTo", input.createdTo]
1196
+ ]) {
1197
+ if (value !== void 0) {
1198
+ assertIdentifier(value, name);
1199
+ query.set(name, value);
1200
+ }
1201
+ }
1202
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
1203
+ return request({
1204
+ method: "GET",
1205
+ path: `/v1/payment-links${suffix}`,
1206
+ signal: input.signal,
1207
+ guard: isPaymentLinkList
1208
+ });
1209
+ };
1210
+ const getPaymentLink = (id, options = {}) => {
1211
+ assertIdentifier(id, "Payment link id");
1212
+ return request({
1213
+ method: "GET",
1214
+ path: `/v1/payment-links/${encodePathSegment(id)}`,
1215
+ signal: options.signal,
1216
+ guard: isPaymentLink
1217
+ });
1218
+ };
1219
+ const updatePaymentLink = (id, input) => {
1220
+ assertIdentifier(id, "Payment link id");
1221
+ assertPaymentLinkFields(input);
1222
+ assertPaymentLinkVersion(input.version);
1223
+ return request({
1224
+ method: "PATCH",
1225
+ path: `/v1/payment-links/${encodePathSegment(id)}`,
1226
+ body: { ...paymentLinkBody(input), version: input.version },
1227
+ idempotencyKey: input.idempotencyKey,
1228
+ signal: input.signal,
1229
+ guard: isPaymentLink
1230
+ });
1231
+ };
1232
+ const paymentLinkAction = (id, action, input = {}) => {
1233
+ assertIdentifier(id, "Payment link id");
1234
+ return request({
1235
+ method: "POST",
1236
+ path: `/v1/payment-links/${encodePathSegment(id)}/${action}`,
1237
+ idempotencyKey: input.idempotencyKey,
1238
+ signal: input.signal,
1239
+ guard: isPaymentLink
1240
+ });
1241
+ };
1242
+ const pausePaymentLink = (id, input = {}) => paymentLinkAction(id, "pause", input);
1243
+ const resumePaymentLink = (id, input = {}) => paymentLinkAction(id, "resume", input);
1244
+ const archivePaymentLink = (id, input = {}) => paymentLinkAction(id, "archive", input);
1245
+ const duplicatePaymentLink = (id, input = {}) => paymentLinkAction(id, "duplicate", input);
1246
+ const releasePaymentLinkReservation = (id, input) => {
1247
+ assertIdentifier(id, "Payment link id");
1248
+ if (input.acknowledgeLatePaymentRisk !== true) {
1249
+ throw new PayclaveError({
1250
+ message: "Payment-link reservation release requires explicit late-payment risk acknowledgement.",
1251
+ code: "INVALID_REQUEST_BODY",
1252
+ status: 0
1253
+ });
1254
+ }
1255
+ return request({
1256
+ method: "POST",
1257
+ path: `/v1/payment-links/${encodePathSegment(id)}/release-reservation`,
1258
+ body: { acknowledgeLatePaymentRisk: input.acknowledgeLatePaymentRisk },
1259
+ idempotencyKey: input.idempotencyKey,
1260
+ signal: input.signal,
1261
+ guard: isPaymentLink
1262
+ });
1263
+ };
1264
+ const listPaymentLinkPayments = (id, input = {}) => {
1265
+ assertIdentifier(id, "Payment link id");
1266
+ const query = new URLSearchParams();
1267
+ if (input.limit !== void 0) {
1268
+ assertPositiveIntegerLimit(input.limit);
1269
+ query.set("limit", String(input.limit));
1270
+ }
1271
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
1272
+ return request({
1273
+ method: "GET",
1274
+ path: `/v1/payment-links/${encodePathSegment(id)}/payments${suffix}`,
1275
+ signal: input.signal,
1276
+ guard: isPaymentLinkPayments
1277
+ });
1278
+ };
740
1279
  const getPayment = (id, options = {}) => {
741
1280
  assertIdentifier(id, "Payment id");
742
1281
  return request({
@@ -760,6 +1299,75 @@ function createPayclaveServerClient({
760
1299
  guard: isWebhookEndpoint
761
1300
  });
762
1301
  };
1302
+ const listWebhookEndpoints = (options = {}) => request({
1303
+ method: "GET",
1304
+ path: "/v1/webhook-endpoints",
1305
+ signal: options.signal,
1306
+ guard: isWebhookEndpointArray
1307
+ });
1308
+ const getWebhookEndpoint = (id, options = {}) => {
1309
+ assertIdentifier(id, "Webhook endpoint id");
1310
+ return request({
1311
+ method: "GET",
1312
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}`,
1313
+ signal: options.signal,
1314
+ guard: isWebhookEndpoint
1315
+ });
1316
+ };
1317
+ const updateWebhookEndpoint = (id, input) => {
1318
+ assertIdentifier(id, "Webhook endpoint id");
1319
+ const url = input.url === void 0 ? void 0 : normalizeWebhookUrl(input.url);
1320
+ assertWebhookEventTypes(input.eventTypes);
1321
+ if (input.alertThreshold !== void 0 && (!Number.isInteger(input.alertThreshold) || input.alertThreshold < 2 || input.alertThreshold > 10)) {
1322
+ throw new PayclaveError({
1323
+ message: "Webhook alert threshold must be between 2 and 10.",
1324
+ code: "INVALID_ARGUMENT",
1325
+ status: 0
1326
+ });
1327
+ }
1328
+ const { signal, idempotencyKey, ...rest } = input;
1329
+ const body = { ...rest, ...url === void 0 ? {} : { url } };
1330
+ return request({
1331
+ method: "PATCH",
1332
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}`,
1333
+ body,
1334
+ idempotencyKey,
1335
+ signal,
1336
+ guard: isWebhookEndpoint
1337
+ });
1338
+ };
1339
+ const archiveWebhookEndpoint = (id, input) => {
1340
+ assertIdentifier(id, "Webhook endpoint id");
1341
+ return request({
1342
+ method: "DELETE",
1343
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}`,
1344
+ idempotencyKey: input.idempotencyKey,
1345
+ signal: input.signal,
1346
+ guard: isWebhookEndpointArchive
1347
+ });
1348
+ };
1349
+ const rotateWebhookSecret = (id, input) => {
1350
+ assertIdentifier(id, "Webhook endpoint id");
1351
+ return request({
1352
+ method: "POST",
1353
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}/rotate-secret`,
1354
+ body: {},
1355
+ idempotencyKey: input.idempotencyKey,
1356
+ signal: input.signal,
1357
+ guard: isWebhookEndpoint
1358
+ });
1359
+ };
1360
+ const endWebhookSecretOverlap = (id, input) => {
1361
+ assertIdentifier(id, "Webhook endpoint id");
1362
+ return request({
1363
+ method: "POST",
1364
+ path: `/v1/webhook-endpoints/${encodePathSegment(id)}/end-secret-overlap`,
1365
+ body: {},
1366
+ idempotencyKey: input.idempotencyKey,
1367
+ signal: input.signal,
1368
+ guard: isWebhookEndpoint
1369
+ });
1370
+ };
763
1371
  const createTestWebhook = (input) => {
764
1372
  assertIdentifier(input.endpointId, "Webhook endpoint id");
765
1373
  assertWebhookEventTypes(
@@ -781,7 +1389,23 @@ function createPayclaveServerClient({
781
1389
  if (limit !== void 0) {
782
1390
  assertPositiveIntegerLimit(limit);
783
1391
  }
784
- const query = limit !== void 0 ? `?limit=${encodeURIComponent(String(limit))}` : "";
1392
+ const params = new URLSearchParams();
1393
+ if (limit !== void 0) params.set("limit", String(limit));
1394
+ for (const [key, value] of [
1395
+ ["endpointId", input.endpointId],
1396
+ ["eventType", input.eventType],
1397
+ ["status", input.status],
1398
+ ["createdFrom", input.createdFrom],
1399
+ ["createdTo", input.createdTo],
1400
+ ["replayStatus", input.replayStatus],
1401
+ ["responseFamily", input.responseFamily]
1402
+ ]) {
1403
+ if (value !== void 0) {
1404
+ assertIdentifier(value, key);
1405
+ params.set(key, value);
1406
+ }
1407
+ }
1408
+ const query = params.size > 0 ? `?${params.toString()}` : "";
785
1409
  return request({
786
1410
  method: "GET",
787
1411
  path: `/v1/webhook-deliveries${query}`,
@@ -789,19 +1413,225 @@ function createPayclaveServerClient({
789
1413
  guard: isWebhookDeliveryArray
790
1414
  });
791
1415
  };
1416
+ const getWebhookDelivery = (id, options = {}) => {
1417
+ assertIdentifier(id, "Webhook delivery id");
1418
+ return request({
1419
+ method: "GET",
1420
+ path: `/v1/webhook-deliveries/${encodePathSegment(id)}`,
1421
+ signal: options.signal,
1422
+ guard: isWebhookDeliveryDetail
1423
+ });
1424
+ };
1425
+ const listWebhookDeliveryAttempts = (id, options = {}) => {
1426
+ assertIdentifier(id, "Webhook delivery id");
1427
+ return request({
1428
+ method: "GET",
1429
+ path: `/v1/webhook-deliveries/${encodePathSegment(id)}/attempts`,
1430
+ signal: options.signal,
1431
+ guard: isWebhookDeliveryAttemptArray
1432
+ });
1433
+ };
1434
+ const replayWebhookDelivery = (id, input) => {
1435
+ assertIdentifier(id, "Webhook delivery id");
1436
+ return request({
1437
+ method: "POST",
1438
+ path: `/v1/webhook-deliveries/${encodePathSegment(id)}/replay`,
1439
+ idempotencyKey: input.idempotencyKey,
1440
+ signal: input.signal,
1441
+ guard: isWebhookDeliveryDetail
1442
+ });
1443
+ };
1444
+ const listWebhookIncidents = (input = {}) => {
1445
+ const query = input.status ? `?status=${input.status}` : "";
1446
+ return request({
1447
+ method: "GET",
1448
+ path: `/v1/webhook-incidents${query}`,
1449
+ signal: input.signal,
1450
+ guard: isWebhookIncidentArray
1451
+ });
1452
+ };
1453
+ const getWebhookIncident = (id, options = {}) => {
1454
+ assertIdentifier(id, "Webhook incident id");
1455
+ return request({
1456
+ method: "GET",
1457
+ path: `/v1/webhook-incidents/${encodePathSegment(id)}`,
1458
+ signal: options.signal,
1459
+ guard: isWebhookIncident
1460
+ });
1461
+ };
1462
+ const getReconciliationSchema = (version = PAYCLAVE_RECONCILIATION_SCHEMA_VERSION, options = {}) => {
1463
+ assertIdentifier(version, "Reconciliation schema version");
1464
+ return request({
1465
+ method: "GET",
1466
+ path: `/v1/reconciliation/schema/${encodePathSegment(version)}`,
1467
+ signal: options.signal,
1468
+ guard: isReconciliationSchema
1469
+ });
1470
+ };
1471
+ const getReconciliationSummary = (input) => {
1472
+ assertIdentifier(input.dateBasis, "Reconciliation date basis");
1473
+ assertIdentifier(input.from, "Reconciliation from timestamp");
1474
+ assertIdentifier(input.to, "Reconciliation to timestamp");
1475
+ const query = new URLSearchParams({
1476
+ dateBasis: input.dateBasis,
1477
+ from: input.from,
1478
+ to: input.to,
1479
+ timezone: input.timezone ?? "UTC"
1480
+ });
1481
+ if (input.exceptionOnly !== void 0) {
1482
+ query.set("exceptionOnly", String(input.exceptionOnly));
1483
+ }
1484
+ for (const status of input.invoiceStatuses ?? []) {
1485
+ query.append("invoiceStatus", status);
1486
+ }
1487
+ for (const status of input.paymentStatuses ?? []) {
1488
+ query.append("paymentStatus", status);
1489
+ }
1490
+ for (const token of input.settlementTokens ?? []) {
1491
+ query.append("settlementToken", token);
1492
+ }
1493
+ return request({
1494
+ method: "GET",
1495
+ path: `/v1/reconciliation/summary?${query.toString()}`,
1496
+ signal: input.signal,
1497
+ guard: isReconciliationSummary
1498
+ });
1499
+ };
1500
+ const createReconciliationExport = (input) => {
1501
+ assertReconciliationFormat(input.format);
1502
+ assertIdentifier(input.dateBasis, "Reconciliation date basis");
1503
+ assertIdentifier(input.from, "Reconciliation from timestamp");
1504
+ assertIdentifier(input.to, "Reconciliation to timestamp");
1505
+ const { signal, idempotencyKey, ...fields } = input;
1506
+ return request({
1507
+ method: "POST",
1508
+ path: "/v1/reconciliation-exports",
1509
+ body: compact({
1510
+ ...fields,
1511
+ mode: input.mode ?? (secretKey.startsWith("sk_live_") ? "live" : "test"),
1512
+ timezone: input.timezone ?? "UTC",
1513
+ exceptionOnly: input.exceptionOnly ?? false,
1514
+ includePII: input.includePII ?? false,
1515
+ schemaVersion: input.schemaVersion ?? PAYCLAVE_RECONCILIATION_SCHEMA_VERSION
1516
+ }),
1517
+ idempotencyKey,
1518
+ signal,
1519
+ guard: isReconciliationExport
1520
+ });
1521
+ };
1522
+ const listReconciliationExports = (input = {}) => {
1523
+ const query = new URLSearchParams();
1524
+ if (input.limit !== void 0) {
1525
+ assertPositiveIntegerLimit(input.limit);
1526
+ query.set("limit", String(input.limit));
1527
+ }
1528
+ if (input.startingAfter !== void 0) {
1529
+ assertIdentifier(input.startingAfter, "Starting reconciliation export id");
1530
+ query.set("startingAfter", input.startingAfter);
1531
+ }
1532
+ const suffix = query.size > 0 ? `?${query.toString()}` : "";
1533
+ return request({
1534
+ method: "GET",
1535
+ path: `/v1/reconciliation-exports${suffix}`,
1536
+ signal: input.signal,
1537
+ guard: isReconciliationExportList
1538
+ });
1539
+ };
1540
+ const getReconciliationExport = (id, options = {}) => {
1541
+ assertIdentifier(id, "Reconciliation export id");
1542
+ return request({
1543
+ method: "GET",
1544
+ path: `/v1/reconciliation-exports/${encodePathSegment(id)}`,
1545
+ signal: options.signal,
1546
+ guard: isReconciliationExport
1547
+ });
1548
+ };
1549
+ const cancelReconciliationExport = (id, input = {}) => {
1550
+ assertIdentifier(id, "Reconciliation export id");
1551
+ return request({
1552
+ method: "POST",
1553
+ path: `/v1/reconciliation-exports/${encodePathSegment(id)}/cancel`,
1554
+ idempotencyKey: input.idempotencyKey,
1555
+ signal: input.signal,
1556
+ guard: isReconciliationExport
1557
+ });
1558
+ };
1559
+ const downloadReconciliationExport = async (id, options = {}) => {
1560
+ assertIdentifier(id, "Reconciliation export id");
1561
+ const response = await runFetch({
1562
+ fetcher,
1563
+ url: joinUrl(
1564
+ normalizedApiBaseUrl,
1565
+ `/v1/reconciliation-exports/${encodePathSegment(id)}/download`
1566
+ ),
1567
+ init: {
1568
+ method: "GET",
1569
+ headers: {
1570
+ Accept: "application/zip",
1571
+ Authorization: `Bearer ${secretKey}`,
1572
+ "X-Payclave-Client": buildClientHeader()
1573
+ }
1574
+ },
1575
+ externalSignal: options.signal,
1576
+ timeoutMs
1577
+ });
1578
+ return parseReconciliationDownloadResponse(response);
1579
+ };
792
1580
  return {
793
1581
  createCheckoutSession,
794
1582
  getCheckoutSession,
795
1583
  createInvoice,
1584
+ createInvoiceDraft,
1585
+ listInvoices,
796
1586
  getInvoice,
1587
+ downloadInvoicePDF,
1588
+ updateInvoiceDraft,
1589
+ issueInvoice,
1590
+ sendInvoice,
1591
+ remindInvoice,
1592
+ createInvoiceCheckoutSession,
1593
+ voidInvoice,
1594
+ voidInvoiceRemaining,
1595
+ markInvoiceUncollectible,
1596
+ duplicateInvoice,
1597
+ recordInvoiceRefundReference,
1598
+ createPaymentLink,
1599
+ listPaymentLinks,
1600
+ getPaymentLink,
1601
+ updatePaymentLink,
1602
+ pausePaymentLink,
1603
+ resumePaymentLink,
1604
+ archivePaymentLink,
1605
+ duplicatePaymentLink,
1606
+ releasePaymentLinkReservation,
1607
+ listPaymentLinkPayments,
797
1608
  getPayment,
798
1609
  createWebhookEndpoint,
1610
+ listWebhookEndpoints,
1611
+ getWebhookEndpoint,
1612
+ updateWebhookEndpoint,
1613
+ archiveWebhookEndpoint,
1614
+ rotateWebhookSecret,
1615
+ endWebhookSecretOverlap,
799
1616
  createTestWebhook,
800
- listWebhookDeliveries
1617
+ listWebhookDeliveries,
1618
+ getWebhookDelivery,
1619
+ listWebhookDeliveryAttempts,
1620
+ replayWebhookDelivery,
1621
+ listWebhookIncidents,
1622
+ getWebhookIncident,
1623
+ getReconciliationSchema,
1624
+ getReconciliationSummary,
1625
+ createReconciliationExport,
1626
+ listReconciliationExports,
1627
+ getReconciliationExport,
1628
+ cancelReconciliationExport,
1629
+ downloadReconciliationExport
801
1630
  };
802
1631
  }
803
1632
 
804
1633
  exports.PAYCLAVE_API_ERROR_CODES = PAYCLAVE_API_ERROR_CODES;
1634
+ exports.PAYCLAVE_RECONCILIATION_SCHEMA_VERSION = PAYCLAVE_RECONCILIATION_SCHEMA_VERSION;
805
1635
  exports.PAYCLAVE_SERVER_SDK_ERROR_CODES = PAYCLAVE_SERVER_SDK_ERROR_CODES;
806
1636
  exports.PAYCLAVE_SERVER_SDK_NAME = PAYCLAVE_SERVER_SDK_NAME;
807
1637
  exports.PAYCLAVE_SERVER_SDK_VERSION = PAYCLAVE_SERVER_SDK_VERSION;