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