mollie-api-typescript 1.4.1 → 1.5.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.
Files changed (103) hide show
  1. package/README.md +57 -0
  2. package/dist/commonjs/funcs/mandatesList.js +1 -0
  3. package/dist/commonjs/funcs/mandatesList.js.map +1 -1
  4. package/dist/commonjs/index.d.ts +1 -0
  5. package/dist/commonjs/index.d.ts.map +1 -1
  6. package/dist/commonjs/index.js +1 -0
  7. package/dist/commonjs/index.js.map +1 -1
  8. package/dist/commonjs/lib/config.d.ts +2 -2
  9. package/dist/commonjs/lib/config.js +2 -2
  10. package/dist/commonjs/models/index.d.ts +1 -0
  11. package/dist/commonjs/models/index.d.ts.map +1 -1
  12. package/dist/commonjs/models/index.js +1 -0
  13. package/dist/commonjs/models/index.js.map +1 -1
  14. package/dist/commonjs/models/listmandateresponse.d.ts +26 -0
  15. package/dist/commonjs/models/listmandateresponse.d.ts.map +1 -1
  16. package/dist/commonjs/models/listmandateresponse.js +15 -1
  17. package/dist/commonjs/models/listmandateresponse.js.map +1 -1
  18. package/dist/commonjs/models/listpaymentresponse.d.ts +3 -3
  19. package/dist/commonjs/models/listsettlementpaymentresponse.d.ts +3 -3
  20. package/dist/commonjs/models/mandateresponse.d.ts +26 -0
  21. package/dist/commonjs/models/mandateresponse.d.ts.map +1 -1
  22. package/dist/commonjs/models/mandateresponse.js +14 -1
  23. package/dist/commonjs/models/mandateresponse.js.map +1 -1
  24. package/dist/commonjs/models/mandatescopes.d.ts +22 -0
  25. package/dist/commonjs/models/mandatescopes.d.ts.map +1 -0
  26. package/dist/commonjs/models/mandatescopes.js +54 -0
  27. package/dist/commonjs/models/mandatescopes.js.map +1 -0
  28. package/dist/commonjs/models/operations/listmandates.d.ts +5 -0
  29. package/dist/commonjs/models/operations/listmandates.d.ts.map +1 -1
  30. package/dist/commonjs/models/operations/listmandates.js +1 -0
  31. package/dist/commonjs/models/operations/listmandates.js.map +1 -1
  32. package/dist/commonjs/models/paymentrequest.d.ts +11 -3
  33. package/dist/commonjs/models/paymentrequest.d.ts.map +1 -1
  34. package/dist/commonjs/models/paymentrequest.js +1 -0
  35. package/dist/commonjs/models/paymentrequest.js.map +1 -1
  36. package/dist/commonjs/models/paymentresponse.d.ts +3 -3
  37. package/dist/commonjs/utils/webhooks/index.d.ts +2 -0
  38. package/dist/commonjs/utils/webhooks/index.d.ts.map +1 -0
  39. package/dist/commonjs/utils/webhooks/index.js +7 -0
  40. package/dist/commonjs/utils/webhooks/index.js.map +1 -0
  41. package/dist/commonjs/utils/webhooks/signature_validator.d.ts +17 -0
  42. package/dist/commonjs/utils/webhooks/signature_validator.d.ts.map +1 -0
  43. package/dist/commonjs/utils/webhooks/signature_validator.js +88 -0
  44. package/dist/commonjs/utils/webhooks/signature_validator.js.map +1 -0
  45. package/dist/esm/funcs/mandatesList.js +1 -0
  46. package/dist/esm/funcs/mandatesList.js.map +1 -1
  47. package/dist/esm/index.d.ts +1 -0
  48. package/dist/esm/index.d.ts.map +1 -1
  49. package/dist/esm/index.js +1 -0
  50. package/dist/esm/index.js.map +1 -1
  51. package/dist/esm/lib/config.d.ts +2 -2
  52. package/dist/esm/lib/config.js +2 -2
  53. package/dist/esm/models/index.d.ts +1 -0
  54. package/dist/esm/models/index.d.ts.map +1 -1
  55. package/dist/esm/models/index.js +1 -0
  56. package/dist/esm/models/index.js.map +1 -1
  57. package/dist/esm/models/listmandateresponse.d.ts +26 -0
  58. package/dist/esm/models/listmandateresponse.d.ts.map +1 -1
  59. package/dist/esm/models/listmandateresponse.js +14 -0
  60. package/dist/esm/models/listmandateresponse.js.map +1 -1
  61. package/dist/esm/models/listpaymentresponse.d.ts +3 -3
  62. package/dist/esm/models/listsettlementpaymentresponse.d.ts +3 -3
  63. package/dist/esm/models/mandateresponse.d.ts +26 -0
  64. package/dist/esm/models/mandateresponse.d.ts.map +1 -1
  65. package/dist/esm/models/mandateresponse.js +13 -0
  66. package/dist/esm/models/mandateresponse.js.map +1 -1
  67. package/dist/esm/models/mandatescopes.d.ts +22 -0
  68. package/dist/esm/models/mandatescopes.d.ts.map +1 -0
  69. package/dist/esm/models/mandatescopes.js +18 -0
  70. package/dist/esm/models/mandatescopes.js.map +1 -0
  71. package/dist/esm/models/operations/listmandates.d.ts +5 -0
  72. package/dist/esm/models/operations/listmandates.d.ts.map +1 -1
  73. package/dist/esm/models/operations/listmandates.js +1 -0
  74. package/dist/esm/models/operations/listmandates.js.map +1 -1
  75. package/dist/esm/models/paymentrequest.d.ts +11 -3
  76. package/dist/esm/models/paymentrequest.d.ts.map +1 -1
  77. package/dist/esm/models/paymentrequest.js +1 -0
  78. package/dist/esm/models/paymentrequest.js.map +1 -1
  79. package/dist/esm/models/paymentresponse.d.ts +3 -3
  80. package/dist/esm/utils/webhooks/index.d.ts +2 -0
  81. package/dist/esm/utils/webhooks/index.d.ts.map +1 -0
  82. package/dist/esm/utils/webhooks/index.js +2 -0
  83. package/dist/esm/utils/webhooks/index.js.map +1 -0
  84. package/dist/esm/utils/webhooks/signature_validator.d.ts +17 -0
  85. package/dist/esm/utils/webhooks/signature_validator.d.ts.map +1 -0
  86. package/dist/esm/utils/webhooks/signature_validator.js +83 -0
  87. package/dist/esm/utils/webhooks/signature_validator.js.map +1 -0
  88. package/jsr.json +1 -1
  89. package/package.json +1 -1
  90. package/src/funcs/mandatesList.ts +1 -0
  91. package/src/index.ts +1 -0
  92. package/src/lib/config.ts +2 -2
  93. package/src/models/index.ts +1 -0
  94. package/src/models/listmandateresponse.ts +36 -0
  95. package/src/models/listpaymentresponse.ts +3 -3
  96. package/src/models/listsettlementpaymentresponse.ts +3 -3
  97. package/src/models/mandateresponse.ts +33 -0
  98. package/src/models/mandatescopes.ts +30 -0
  99. package/src/models/operations/listmandates.ts +6 -0
  100. package/src/models/paymentrequest.ts +12 -3
  101. package/src/models/paymentresponse.ts +3 -3
  102. package/src/utils/webhooks/index.ts +4 -0
  103. package/src/utils/webhooks/signature_validator.ts +136 -0
@@ -1027,12 +1027,12 @@ export type ListSettlementPaymentResponse = {
1027
1027
  */
1028
1028
  subscriptionId?: string | null | undefined;
1029
1029
  /**
1030
- * **Only relevant for recurring payments.**
1030
+ * **Only relevant for recurring payments and stored cards.**
1031
1031
  *
1032
1032
  * @remarks
1033
1033
  *
1034
- * When creating recurring payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
1035
- * the customer's accounts should be credited.
1034
+ * When creating recurring or stored cards payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
1035
+ * the customer's accounts should be debited.
1036
1036
  */
1037
1037
  mandateId?: string | null | undefined;
1038
1038
  customerId?: string | undefined;
@@ -59,6 +59,24 @@ export type MandateResponseDetails = {
59
59
  cardFingerprint?: string | null | undefined;
60
60
  };
61
61
 
62
+ /**
63
+ * An array defining the eligible use cases for the mandate. For creditcard mandates, this field will always be
64
+ *
65
+ * @remarks
66
+ * present and can contain one or both of the following values:
67
+ */
68
+ export const MandateResponseScope = {
69
+ CustomerPresent: "customer-present",
70
+ CustomerNotPresent: "customer-not-present",
71
+ } as const;
72
+ /**
73
+ * An array defining the eligible use cases for the mandate. For creditcard mandates, this field will always be
74
+ *
75
+ * @remarks
76
+ * present and can contain one or both of the following values:
77
+ */
78
+ export type MandateResponseScope = OpenEnum<typeof MandateResponseScope>;
79
+
62
80
  /**
63
81
  * The status of the mandate. A status can be `pending` for mandates when the first payment is not yet finalized, or
64
82
  *
@@ -129,6 +147,13 @@ export type MandateResponse = {
129
147
  * decline Direct Debit payments if the mandate reference is not unique.
130
148
  */
131
149
  mandateReference: string | null;
150
+ /**
151
+ * An array defining the eligible use cases for the mandate. This field will always be
152
+ *
153
+ * @remarks
154
+ * present and can contain one or both of the following values:
155
+ */
156
+ scopes?: Array<MandateResponseScope> | null | undefined;
132
157
  status: MandateResponseStatus;
133
158
  /**
134
159
  * The identifier referring to the [customer](get-customer) this mandate was linked to.
@@ -171,6 +196,13 @@ export function mandateResponseDetailsFromJSON(
171
196
  );
172
197
  }
173
198
 
199
+ /** @internal */
200
+ export const MandateResponseScope$inboundSchema: z.ZodType<
201
+ MandateResponseScope,
202
+ z.ZodTypeDef,
203
+ unknown
204
+ > = openEnums.inboundSchema(MandateResponseScope);
205
+
174
206
  /** @internal */
175
207
  export const MandateResponseStatus$inboundSchema: z.ZodType<
176
208
  MandateResponseStatus,
@@ -212,6 +244,7 @@ export const MandateResponse$inboundSchema: z.ZodType<
212
244
  details: z.lazy(() => MandateResponseDetails$inboundSchema),
213
245
  signatureDate: z.nullable(z.string()),
214
246
  mandateReference: z.nullable(z.string()),
247
+ scopes: z.nullable(z.array(MandateResponseScope$inboundSchema)).optional(),
215
248
  status: MandateResponseStatus$inboundSchema,
216
249
  customerId: z.string(),
217
250
  createdAt: z.string(),
@@ -0,0 +1,30 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ * @generated-id: 578dd7beb9f7
4
+ */
5
+
6
+ import * as z from "zod/v3";
7
+ import { ClosedEnum } from "../types/enums.js";
8
+
9
+ /**
10
+ * An array defining the eligible use cases for the mandate. For creditcard mandates, this field will always be
11
+ *
12
+ * @remarks
13
+ * present and can contain one or both of the following values:
14
+ */
15
+ export const MandateScopes = {
16
+ CustomerPresent: "customer-present",
17
+ CustomerNotPresent: "customer-not-present",
18
+ } as const;
19
+ /**
20
+ * An array defining the eligible use cases for the mandate. For creditcard mandates, this field will always be
21
+ *
22
+ * @remarks
23
+ * present and can contain one or both of the following values:
24
+ */
25
+ export type MandateScopes = ClosedEnum<typeof MandateScopes>;
26
+
27
+ /** @internal */
28
+ export const MandateScopes$outboundSchema: z.ZodNativeEnum<
29
+ typeof MandateScopes
30
+ > = z.nativeEnum(MandateScopes);
@@ -46,6 +46,10 @@ export type ListMandatesRequest = {
46
46
  * newest to oldest.
47
47
  */
48
48
  sort?: models.Sorting | undefined;
49
+ /**
50
+ * Returns only mandates that include the specified scopes.
51
+ */
52
+ scopes?: Array<models.MandateScopes> | undefined;
49
53
  /**
50
54
  * Most API credentials are specifically created for either live mode or test mode. In those cases the `testmode` query
51
55
  *
@@ -100,6 +104,7 @@ export type ListMandatesRequest$Outbound = {
100
104
  from?: string | undefined;
101
105
  limit?: number | null | undefined;
102
106
  sort?: string | undefined;
107
+ scopes?: Array<string> | undefined;
103
108
  testmode?: boolean | undefined;
104
109
  "idempotency-key"?: string | undefined;
105
110
  };
@@ -114,6 +119,7 @@ export const ListMandatesRequest$outboundSchema: z.ZodType<
114
119
  from: z.string().optional(),
115
120
  limit: z.nullable(z.number().int()).optional(),
116
121
  sort: models.Sorting$outboundSchema.optional(),
122
+ scopes: z.array(models.MandateScopes$outboundSchema).optional(),
117
123
  testmode: z.boolean().optional(),
118
124
  idempotencyKey: z.string().optional(),
119
125
  }).transform((v) => {
@@ -445,12 +445,12 @@ export type PaymentRequest = {
445
445
  routing?: Array<EntityPaymentRoute> | null | undefined;
446
446
  sequenceType?: SequenceType | undefined;
447
447
  /**
448
- * **Only relevant for recurring payments.**
448
+ * **Only relevant for recurring payments and stored cards.**
449
449
  *
450
450
  * @remarks
451
451
  *
452
- * When creating recurring payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
453
- * the customer's accounts should be credited.
452
+ * When creating recurring or stored cards payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
453
+ * the customer's accounts should be debited.
454
454
  */
455
455
  mandateId?: string | null | undefined;
456
456
  customerId?: string | undefined;
@@ -468,6 +468,13 @@ export type PaymentRequest = {
468
468
  * The date by which the payment should be completed in `YYYY-MM-DD` format
469
469
  */
470
470
  dueDate?: string | undefined;
471
+ /**
472
+ * Whether the card details should be stored for the customer after a successful payment. This will create a mandate for the customer,
473
+ *
474
+ * @remarks
475
+ * allowing for future customer present saved-card CIT payments. Requires customerId, cardToken, and the creditcard method to be specified.
476
+ */
477
+ storeCredentials?: boolean | undefined;
471
478
  /**
472
479
  * Whether to create the entity in test mode or live mode.
473
480
  *
@@ -740,6 +747,7 @@ export type PaymentRequest$Outbound = {
740
747
  customerId?: string | undefined;
741
748
  profileId?: string | undefined;
742
749
  dueDate?: string | undefined;
750
+ storeCredentials?: boolean | undefined;
743
751
  testmode?: boolean | null | undefined;
744
752
  applePayPaymentToken?: string | undefined;
745
753
  company?: Company$Outbound | undefined;
@@ -791,6 +799,7 @@ export const PaymentRequest$outboundSchema: z.ZodType<
791
799
  customerId: z.string().optional(),
792
800
  profileId: z.string().optional(),
793
801
  dueDate: z.string().optional(),
802
+ storeCredentials: z.boolean().optional(),
794
803
  testmode: z.nullable(z.boolean()).optional(),
795
804
  applePayPaymentToken: z.string().optional(),
796
805
  company: z.lazy(() => Company$outboundSchema).optional(),
@@ -1044,12 +1044,12 @@ export type PaymentResponse = {
1044
1044
  */
1045
1045
  subscriptionId?: string | null | undefined;
1046
1046
  /**
1047
- * **Only relevant for recurring payments.**
1047
+ * **Only relevant for recurring payments and stored cards.**
1048
1048
  *
1049
1049
  * @remarks
1050
1050
  *
1051
- * When creating recurring payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
1052
- * the customer's accounts should be credited.
1051
+ * When creating recurring or stored cards payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
1052
+ * the customer's accounts should be debited.
1053
1053
  */
1054
1054
  mandateId?: string | null | undefined;
1055
1055
  customerId?: string | undefined;
@@ -0,0 +1,4 @@
1
+ export {
2
+ InvalidSignatureException,
3
+ SignatureValidator,
4
+ } from "./signature_validator.js";
@@ -0,0 +1,136 @@
1
+ export class InvalidSignatureException extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = "InvalidSignatureException";
5
+
6
+ Object.setPrototypeOf(this, InvalidSignatureException.prototype);
7
+ }
8
+ }
9
+
10
+ export class SignatureValidator {
11
+ static readonly SIGNATURE_HEADER = "X-Mollie-Signature";
12
+ private static readonly SIGNATURE_PREFIX = "sha256=";
13
+
14
+ private readonly signingSecrets: string[];
15
+
16
+ constructor(signingSecrets: string | string[]) {
17
+ this.signingSecrets = Array.isArray(signingSecrets)
18
+ ? [...signingSecrets]
19
+ : [signingSecrets];
20
+ }
21
+
22
+ static async validate(
23
+ payload: string,
24
+ signingSecrets: string | string[],
25
+ signatures?: string | string[] | null,
26
+ ): Promise<boolean> {
27
+ return new SignatureValidator(signingSecrets).validatePayload(
28
+ payload,
29
+ signatures,
30
+ );
31
+ }
32
+
33
+ async validatePayload(
34
+ payload: string,
35
+ signatures?: string | string[] | null,
36
+ ): Promise<boolean> {
37
+ const signatureList = this.normalizeSignatures(signatures);
38
+
39
+ if (signatureList.length === 0) {
40
+ return false;
41
+ }
42
+
43
+ return this.validateSignatures(payload, signatureList);
44
+ }
45
+
46
+ private normalizeSignatures(
47
+ signatures?: string | string[] | null,
48
+ ): string[] {
49
+ if (typeof signatures === "string") {
50
+ return signatures ? [signatures] : [];
51
+ }
52
+
53
+ if (!signatures) {
54
+ return [];
55
+ }
56
+
57
+ return signatures.filter((signature): signature is string => !!signature);
58
+ }
59
+
60
+ private async validateSignatures(
61
+ payload: string,
62
+ signatures: string[],
63
+ ): Promise<boolean> {
64
+ for (const signature of signatures) {
65
+ const extractedSignature = this.extractSignature(signature);
66
+
67
+ if (await this.isValidSignature(extractedSignature, payload)) {
68
+ return true;
69
+ }
70
+ }
71
+
72
+ throw new InvalidSignatureException("Invalid webhook signature");
73
+ }
74
+
75
+ private extractSignature(signatureHeader: string): string {
76
+ if (signatureHeader.startsWith(SignatureValidator.SIGNATURE_PREFIX)) {
77
+ return signatureHeader.slice(SignatureValidator.SIGNATURE_PREFIX.length);
78
+ }
79
+
80
+ return signatureHeader;
81
+ }
82
+
83
+ private async isValidSignature(
84
+ providedSignature: string,
85
+ payload: string,
86
+ ): Promise<boolean> {
87
+ for (const secret of this.signingSecrets) {
88
+ const expectedSignature = await SignatureValidator.createSignature(
89
+ payload,
90
+ secret,
91
+ );
92
+
93
+ if (constantTimeEquals(expectedSignature, providedSignature)) {
94
+ return true;
95
+ }
96
+ }
97
+
98
+ return false;
99
+ }
100
+
101
+ static async createSignature(payload: string, secret: string): Promise<string> {
102
+ const subtle = globalThis.crypto?.subtle;
103
+ if (!subtle) {
104
+ throw new Error("Web Crypto API is not available in this runtime");
105
+ }
106
+
107
+ const encoder = new TextEncoder();
108
+ const key = await subtle.importKey(
109
+ "raw",
110
+ encoder.encode(secret),
111
+ { name: "HMAC", hash: "SHA-256" },
112
+ false,
113
+ ["sign"],
114
+ );
115
+ const signature = await subtle.sign("HMAC", key, encoder.encode(payload));
116
+
117
+ return toHex(signature);
118
+ }
119
+ }
120
+
121
+ function constantTimeEquals(left: string, right: string): boolean {
122
+ const maxLength = Math.max(left.length, right.length);
123
+ let mismatch = left.length ^ right.length;
124
+
125
+ for (let index = 0; index < maxLength; index++) {
126
+ mismatch |= (left.charCodeAt(index) || 0) ^ (right.charCodeAt(index) || 0);
127
+ }
128
+
129
+ return mismatch === 0;
130
+ }
131
+
132
+ function toHex(buffer: ArrayBuffer): string {
133
+ return Array.from(new Uint8Array(buffer))
134
+ .map((value) => value.toString(16).padStart(2, "0"))
135
+ .join("");
136
+ }