@dalmore/api-contracts 0.0.0-dev.988f3c3 → 0.0.0-dev.9d42e16

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 (191) hide show
  1. package/README.md +23 -19
  2. package/common/types/account-contact.types.ts +2 -1
  3. package/common/types/account-manager.types.ts +3 -7
  4. package/common/types/account.types.ts +1 -0
  5. package/common/types/auth.types.ts +7 -18
  6. package/common/types/common.types.ts +22 -0
  7. package/common/types/comply-advantage-api.types.ts +3 -3
  8. package/common/types/contact-us.types.ts +6 -2
  9. package/common/types/covered-person.types.ts +2 -1
  10. package/common/types/escrow-account.types.ts +3 -3
  11. package/common/types/individuals.types.ts +3 -2
  12. package/common/types/investor-account.types.ts +2 -1
  13. package/common/types/invite.types.ts +27 -1
  14. package/common/types/legal-entity.types.ts +3 -2
  15. package/common/types/mail-template.types.ts +34 -0
  16. package/common/types/note.types.ts +1 -1
  17. package/common/types/notification.types.ts +10 -0
  18. package/common/types/site-settings.types.ts +2 -1
  19. package/common/types/trade.types.ts +49 -1
  20. package/common/types/trusted-contact.types.ts +7 -7
  21. package/common/types/user.types.ts +2 -5
  22. package/common/types/webhook.types.ts +142 -0
  23. package/index.ts +10 -0
  24. package/package.json +23 -32
  25. package/contracts/compliance/account-contacts/index.ts +0 -82
  26. package/contracts/compliance/account-managers/index.ts +0 -142
  27. package/contracts/compliance/account-settings/index.ts +0 -59
  28. package/contracts/compliance/accounts/index.ts +0 -187
  29. package/contracts/compliance/activities/index.ts +0 -55
  30. package/contracts/compliance/aic/index.ts +0 -60
  31. package/contracts/compliance/api-keys/index.ts +0 -91
  32. package/contracts/compliance/assets/index.ts +0 -122
  33. package/contracts/compliance/auth/index.ts +0 -134
  34. package/contracts/compliance/batch-jobs/index.ts +0 -62
  35. package/contracts/compliance/bonus-tiers/index.ts +0 -74
  36. package/contracts/compliance/checklist/index.ts +0 -87
  37. package/contracts/compliance/checklist-items/index.ts +0 -86
  38. package/contracts/compliance/covered-persons/index.ts +0 -97
  39. package/contracts/compliance/dashboard/index.ts +0 -111
  40. package/contracts/compliance/data-records/index.ts +0 -116
  41. package/contracts/compliance/data-rooms/index.ts +0 -113
  42. package/contracts/compliance/default-theme-configs/index.ts +0 -95
  43. package/contracts/compliance/disbursement/index.ts +0 -165
  44. package/contracts/compliance/disbursement-approval-users/index.ts +0 -84
  45. package/contracts/compliance/disbursement-transactions/index.ts +0 -37
  46. package/contracts/compliance/domain-filters/index.ts +0 -117
  47. package/contracts/compliance/email-themes/index.ts +0 -284
  48. package/contracts/compliance/escrow-accounts/index.ts +0 -85
  49. package/contracts/compliance/exchange-api-keys/index.ts +0 -129
  50. package/contracts/compliance/exchange-imports/index.ts +0 -137
  51. package/contracts/compliance/files/index.ts +0 -267
  52. package/contracts/compliance/files-public/index.ts +0 -188
  53. package/contracts/compliance/health/index.ts +0 -26
  54. package/contracts/compliance/index.ts +0 -151
  55. package/contracts/compliance/individuals/index.ts +0 -57
  56. package/contracts/compliance/investor-accounts/index.ts +0 -141
  57. package/contracts/compliance/invites/index.ts +0 -137
  58. package/contracts/compliance/issuer-bank-accounts/index.ts +0 -81
  59. package/contracts/compliance/issuer-payment-methods/index.ts +0 -81
  60. package/contracts/compliance/issuers/index.ts +0 -97
  61. package/contracts/compliance/job-items/index.ts +0 -58
  62. package/contracts/compliance/jobs/index.ts +0 -59
  63. package/contracts/compliance/kyb/index.ts +0 -54
  64. package/contracts/compliance/kyc/index.ts +0 -77
  65. package/contracts/compliance/legal-entities/index.ts +0 -57
  66. package/contracts/compliance/login-histories/index.ts +0 -37
  67. package/contracts/compliance/notes/index.ts +0 -69
  68. package/contracts/compliance/notification-channels/index.ts +0 -251
  69. package/contracts/compliance/notion-databases/index.ts +0 -107
  70. package/contracts/compliance/notion-pages/index.ts +0 -105
  71. package/contracts/compliance/offering-reports/index.ts +0 -149
  72. package/contracts/compliance/offerings/index.ts +0 -233
  73. package/contracts/compliance/pages/index.ts +0 -178
  74. package/contracts/compliance/payment-methods/index.ts +0 -57
  75. package/contracts/compliance/rejection-reasons/index.ts +0 -32
  76. package/contracts/compliance/review/index.ts +0 -169
  77. package/contracts/compliance/roles/index.ts +0 -34
  78. package/contracts/compliance/secondary-customers/index.ts +0 -77
  79. package/contracts/compliance/secondary-orders/index.ts +0 -60
  80. package/contracts/compliance/secondary-trades/index.ts +0 -100
  81. package/contracts/compliance/secure-requests/index.ts +0 -54
  82. package/contracts/compliance/signer/index.ts +0 -369
  83. package/contracts/compliance/site-links/index.ts +0 -128
  84. package/contracts/compliance/site-settings/index.ts +0 -669
  85. package/contracts/compliance/sites/index.ts +0 -56
  86. package/contracts/compliance/state-machine/index.ts +0 -94
  87. package/contracts/compliance/tasks/index.ts +0 -91
  88. package/contracts/compliance/third-parties/index.ts +0 -52
  89. package/contracts/compliance/trade-line-items/index.ts +0 -59
  90. package/contracts/compliance/trades/index.ts +0 -230
  91. package/contracts/compliance/transactions/index.ts +0 -161
  92. package/contracts/compliance/user-manuals/index.ts +0 -271
  93. package/contracts/compliance/user-settings/index.ts +0 -189
  94. package/contracts/compliance/users/index.ts +0 -221
  95. package/contracts/compliance/webhooks/index.ts +0 -41
  96. package/contracts/compliance-apikey/accounts/index.ts +0 -58
  97. package/contracts/compliance-apikey/index.ts +0 -14
  98. package/contracts/index.ts +0 -6
  99. package/contracts/investors/account-contacts/index.ts +0 -58
  100. package/contracts/investors/aic/index.ts +0 -59
  101. package/contracts/investors/assets/index.ts +0 -61
  102. package/contracts/investors/auth/index.ts +0 -116
  103. package/contracts/investors/bonus-tiers/index.ts +0 -55
  104. package/contracts/investors/cart/index.ts +0 -75
  105. package/contracts/investors/contact-us/index.ts +0 -48
  106. package/contracts/investors/data-records/index.ts +0 -113
  107. package/contracts/investors/data-rooms/index.ts +0 -96
  108. package/contracts/investors/files/index.ts +0 -167
  109. package/contracts/investors/files-public/index.ts +0 -185
  110. package/contracts/investors/index.ts +0 -72
  111. package/contracts/investors/individuals/index.ts +0 -121
  112. package/contracts/investors/investor-accounts/index.ts +0 -110
  113. package/contracts/investors/issuer-payment-methods/index.ts +0 -36
  114. package/contracts/investors/issuers/index.ts +0 -30
  115. package/contracts/investors/legal-entities/index.ts +0 -93
  116. package/contracts/investors/notes/index.ts +0 -69
  117. package/contracts/investors/offerings/index.ts +0 -93
  118. package/contracts/investors/pages/index.ts +0 -88
  119. package/contracts/investors/payment-methods/index.ts +0 -149
  120. package/contracts/investors/portfolios/index.ts +0 -53
  121. package/contracts/investors/sites/index.ts +0 -96
  122. package/contracts/investors/tasks/index.ts +0 -111
  123. package/contracts/investors/trade-line-items/index.ts +0 -75
  124. package/contracts/investors/trades/index.ts +0 -114
  125. package/contracts/investors/transactions/index.ts +0 -37
  126. package/contracts/investors/trusted-contacts/index.ts +0 -93
  127. package/contracts/investors/user-manuals/index.ts +0 -62
  128. package/contracts/investors/user-settings/index.ts +0 -170
  129. package/contracts/investors/users/index.ts +0 -45
  130. package/contracts/investors/webhooks/index.ts +0 -30
  131. package/contracts/issuers/account-contacts/index.ts +0 -76
  132. package/contracts/issuers/account-integrations/index.ts +0 -97
  133. package/contracts/issuers/account-settings/index.ts +0 -36
  134. package/contracts/issuers/accounts/index.ts +0 -97
  135. package/contracts/issuers/activities/index.ts +0 -54
  136. package/contracts/issuers/aic/index.ts +0 -39
  137. package/contracts/issuers/api-key-logs/index.ts +0 -53
  138. package/contracts/issuers/api-keys/index.ts +0 -93
  139. package/contracts/issuers/assets/index.ts +0 -122
  140. package/contracts/issuers/auth/index.ts +0 -152
  141. package/contracts/issuers/bonus-tiers/index.ts +0 -73
  142. package/contracts/issuers/contact-us/index.ts +0 -48
  143. package/contracts/issuers/covered-persons/index.ts +0 -136
  144. package/contracts/issuers/dashboard/index.ts +0 -72
  145. package/contracts/issuers/data-records/index.ts +0 -257
  146. package/contracts/issuers/data-rooms/index.ts +0 -134
  147. package/contracts/issuers/disbursement-approval-users/index.ts +0 -82
  148. package/contracts/issuers/disbursement-transactions/index.ts +0 -53
  149. package/contracts/issuers/disbursements/index.ts +0 -189
  150. package/contracts/issuers/email-themes/index.ts +0 -242
  151. package/contracts/issuers/escrow-accounts/index.ts +0 -81
  152. package/contracts/issuers/exchange-api-keys/index.ts +0 -144
  153. package/contracts/issuers/files/index.ts +0 -166
  154. package/contracts/issuers/files-public/index.ts +0 -166
  155. package/contracts/issuers/health/index.ts +0 -24
  156. package/contracts/issuers/index.ts +0 -116
  157. package/contracts/issuers/investor-accounts/index.ts +0 -148
  158. package/contracts/issuers/invites/index.ts +0 -129
  159. package/contracts/issuers/issuer/index.ts +0 -94
  160. package/contracts/issuers/issuer-bank-accounts/index.ts +0 -81
  161. package/contracts/issuers/issuer-payment-methods/index.ts +0 -136
  162. package/contracts/issuers/kyc/index.ts +0 -38
  163. package/contracts/issuers/login-histories/index.ts +0 -51
  164. package/contracts/issuers/notes/index.ts +0 -69
  165. package/contracts/issuers/notification-channels/index.ts +0 -251
  166. package/contracts/issuers/offerings/index.ts +0 -206
  167. package/contracts/issuers/pages/index.ts +0 -138
  168. package/contracts/issuers/payment-methods/index.ts +0 -61
  169. package/contracts/issuers/portfolios/index.ts +0 -36
  170. package/contracts/issuers/rejection-reasons/index.ts +0 -32
  171. package/contracts/issuers/review/index.ts +0 -63
  172. package/contracts/issuers/secondary-customers/index.ts +0 -55
  173. package/contracts/issuers/secondary-orders/index.ts +0 -57
  174. package/contracts/issuers/secondary-trades/index.ts +0 -57
  175. package/contracts/issuers/secure-requests/index.ts +0 -34
  176. package/contracts/issuers/site-links/index.ts +0 -116
  177. package/contracts/issuers/site-settings/index.ts +0 -585
  178. package/contracts/issuers/sites/index.ts +0 -32
  179. package/contracts/issuers/tasks/index.ts +0 -111
  180. package/contracts/issuers/trades/index.ts +0 -132
  181. package/contracts/issuers/transactions/index.ts +0 -158
  182. package/contracts/issuers/user-manuals/index.ts +0 -62
  183. package/contracts/issuers/user-settings/index.ts +0 -170
  184. package/contracts/issuers/users/index.ts +0 -126
  185. package/contracts/secondaries/accounts/index.ts +0 -58
  186. package/contracts/secondaries/index.ts +0 -23
  187. package/contracts/secondaries/secondary-customers/index.ts +0 -55
  188. package/contracts/secondaries/secondary-issuers/index.ts +0 -94
  189. package/contracts/secondaries/secondary-orders/index.ts +0 -56
  190. package/contracts/secondaries/secondary-securities/index.ts +0 -95
  191. package/contracts/secondaries/secondary-trades/index.ts +0 -56
package/README.md CHANGED
@@ -14,32 +14,33 @@ npm install @dalmore/api-contracts@dev
14
14
 
15
15
  ## Usage
16
16
 
17
- ### Import specific contracts (recommended for tree-shaking)
17
+ ### Import from main entry
18
18
 
19
19
  ```typescript
20
- import { complianceContract } from '@dalmore/api-contracts/compliance';
21
- import { investorsContract } from '@dalmore/api-contracts/investors';
22
- import { issuersContract } from '@dalmore/api-contracts/issuers';
23
- import { clientsContract } from '@dalmore/api-contracts/clients';
20
+ import { clientsContract } from '@dalmore/api-contracts';
21
+ import type { IInvestorAccount } from '@dalmore/api-contracts';
24
22
  ```
25
23
 
26
- ### Import types
24
+ ### Import specific subpaths (recommended for tree-shaking)
27
25
 
28
26
  ```typescript
29
- import type { IInvestorAccount } from '@dalmore/api-contracts/types/investor-account.types';
30
- import type { ITrade } from '@dalmore/api-contracts/types/trade.types';
27
+ // Import clients contract
28
+ import { clientsContract } from '@dalmore/api-contracts/clients';
29
+
30
+ // Import types
31
+ import type { IInvestorAccount, ITrade } from '@dalmore/api-contracts/types';
31
32
  ```
32
33
 
33
34
  ### Create a typed client
34
35
 
35
36
  ```typescript
36
- import { complianceContract } from '@dalmore/api-contracts/compliance';
37
+ import { clientsContract } from '@dalmore/api-contracts/clients';
37
38
  import { initClient } from '@ts-rest/core';
38
39
 
39
- const client = initClient(complianceContract, {
40
+ const client = initClient(clientsContract, {
40
41
  baseUrl: 'https://platform.dalmoregroup.com',
41
42
  baseHeaders: {
42
- Authorization: `Bearer ${token}`,
43
+ 'X-API-Key': `${apiKey}`,
43
44
  },
44
45
  });
45
46
 
@@ -53,17 +54,20 @@ const { status, body } = await client.accounts.getAccounts({
53
54
 
54
55
  This package requires the following peer dependencies:
55
56
 
56
- - `@ts-rest/core` ^3.0.0
57
- - `zod` ^3.0.0
57
+ - `@anatine/zod-openapi` ^1.14.2
58
+ - `@ts-rest/core` ^3.52.1
59
+ - `typeid-js` ^1.2.0
60
+ - `zod` ^3.24.4
58
61
 
59
- ## Available Contracts
62
+ ## Available Exports
60
63
 
61
- - `complianceContract` - Compliance portal API
62
- - `investorsContract` - Investor portal API
63
- - `issuersContract` - Issuer portal API
64
64
  - `clientsContract` - Client API (API key auth)
65
- - `secondariesContract` - Secondaries API
66
- - `complianceApiKeyContract` - Compliance API (API key auth)
65
+
66
+ ## Available Subpath Exports
67
+
68
+ - `@dalmore/api-contracts` - Main entry (clients contract and types)
69
+ - `@dalmore/api-contracts/clients` - Clients contract
70
+ - `@dalmore/api-contracts/types` - All common types
67
71
 
68
72
  ## TypeScript Configuration
69
73
 
@@ -6,6 +6,7 @@ import { PhoneZodSchema } from './phone.type';
6
6
  import {
7
7
  AccountContactType,
8
8
  AccountZod,
9
+ EmailSchema,
9
10
  IPaginationMeta,
10
11
  } from './common.types';
11
12
  import { IBaseEntity } from './entity.types';
@@ -60,7 +61,7 @@ export const PatchAccountContactZod = z.object({
60
61
  .openapi({ example: 'Mr' }),
61
62
  firstName: z.string().min(1).max(150).openapi({ example: 'John' }),
62
63
  lastName: z.string().min(1).max(150).openapi({ example: 'Doe' }),
63
- email: z.string().email().openapi({ example: 'john.doe@example.com' }),
64
+ email: EmailSchema.openapi({ example: 'john.doe@example.com' }),
64
65
  phone: PhoneZodSchema.nullable()
65
66
  .optional()
66
67
  .openapi({ example: '+12124567890' }),
@@ -4,7 +4,7 @@ import { TypeID } from 'typeid-js';
4
4
  import { IBaseEntity } from './entity.types';
5
5
  import { PhoneNumberData } from './sms.types';
6
6
  import { userIdSchema, UserZod } from './user.types';
7
- import { IPaginationMeta } from './common.types';
7
+ import { EmailSchema, IPaginationMeta } from './common.types';
8
8
  import { PhoneZodSchema } from './phone.type';
9
9
 
10
10
  extendZodWithOpenApi(z);
@@ -68,7 +68,7 @@ export type IAccountManagerZod = z.infer<typeof IAccountManagerZod>;
68
68
  export const PostAccountManagerZod = z.object({
69
69
  firstName: z.string().min(1).max(255).openapi({ example: 'John' }),
70
70
  lastName: z.string().min(1).max(255).openapi({ example: 'Doe' }),
71
- email: z.string().email().openapi({ example: 'john.doe@example.com' }),
71
+ email: EmailSchema,
72
72
  phone: PhoneZodSchema.nullable()
73
73
  .optional()
74
74
  .openapi({ example: '+12124567890' }),
@@ -80,11 +80,7 @@ export type PostAccountManagerZod = z.infer<typeof PostAccountManagerZod>;
80
80
  export const PatchAccountManagerZod = z.object({
81
81
  firstName: z.string().min(1).max(255).optional().openapi({ example: 'John' }),
82
82
  lastName: z.string().min(1).max(255).optional().openapi({ example: 'Doe' }),
83
- email: z
84
- .string()
85
- .email()
86
- .optional()
87
- .openapi({ example: 'john.doe@example.com' }),
83
+ email: EmailSchema.optional(),
88
84
  phone: PhoneZodSchema.nullable()
89
85
  .optional()
90
86
  .openapi({ example: '+12124567890' }),
@@ -101,6 +101,7 @@ const accountsInclude = z.enum([
101
101
  'issuers',
102
102
  'legalEntities',
103
103
  'offerings',
104
+ 'pages',
104
105
  'sites',
105
106
  'trades',
106
107
  'users',
@@ -8,6 +8,7 @@ import {
8
8
  ManagedByType,
9
9
  UserRole,
10
10
  createUrlSchema,
11
+ EmailSchema,
11
12
  } from './common.types';
12
13
  import { TypeID } from 'typeid-js';
13
14
  import { TwoFactorMethod } from './sms.types';
@@ -60,13 +61,7 @@ const BaseAuthBody = z.object({
60
61
  .openapi({
61
62
  example: 'Armstrong',
62
63
  }),
63
- email: z
64
- .string()
65
- .email()
66
- .transform((val) => val.toLowerCase())
67
- .openapi({
68
- example: 'neil@dalmoregroup.com',
69
- }),
64
+ email: EmailSchema,
70
65
  password: PasswordSchema,
71
66
  });
72
67
 
@@ -99,13 +94,7 @@ export const IChangePasswordBodyZod = z
99
94
  });
100
95
 
101
96
  export const LoginBody = z.object({
102
- email: z
103
- .string()
104
- .email()
105
- .transform((val) => val.toLowerCase())
106
- .openapi({
107
- example: 'neil@dalmoregroup.com',
108
- }),
97
+ email: EmailSchema,
109
98
  password: z.string().openapi({
110
99
  example: 'Secretpassword6#',
111
100
  }),
@@ -297,7 +286,7 @@ export const RegisterBodyInvestors = BaseAuthBody.extend({
297
286
  });
298
287
 
299
288
  export const ResetPasswordVerifyBody = z.object({
300
- email: z.string().email(),
289
+ email: EmailSchema,
301
290
  code: z.string().length(6, 'code is not 6 characters').openapi({
302
291
  example: '123456',
303
292
  }),
@@ -315,7 +304,7 @@ export type ResetPasswordVerifyResponseType = z.infer<
315
304
  >;
316
305
 
317
306
  export const ResetPasswordBody = z.object({
318
- email: z.string().email(),
307
+ email: EmailSchema,
319
308
  code: z.string().length(6, 'code is not 6 characters').openapi({
320
309
  example: '123456',
321
310
  }),
@@ -337,7 +326,7 @@ export type ClientAuthSuccessResponse = z.infer<
337
326
  >;
338
327
 
339
328
  export const AdminForgotPasswordRequestZod = z.object({
340
- email: z.string().email(),
329
+ email: EmailSchema,
341
330
  portal: z.nativeEnum(PortalType),
342
331
  });
343
332
  export type AdminForgotPasswordRequestZod = z.infer<
@@ -345,7 +334,7 @@ export type AdminForgotPasswordRequestZod = z.infer<
345
334
  >;
346
335
 
347
336
  export const InvestorForgotPasswordRequestZod = z.object({
348
- email: z.string().email(),
337
+ email: EmailSchema,
349
338
  url: createUrlSchema({ strict: true }),
350
339
  });
351
340
  export type InvestorForgotPasswordRequestZod = z.infer<
@@ -69,6 +69,10 @@ export enum BaseStatus {
69
69
  VOIDED = 'VOIDED',
70
70
  JOIN = 'JOIN',
71
71
  RESTORE = 'RESTORE',
72
+ ACTIVE = 'ACTIVE',
73
+ LOCKED = 'LOCKED',
74
+ ENABLED = 'ENABLED',
75
+ DISABLED = 'DISABLED',
72
76
  }
73
77
 
74
78
  export const UserWithoutPasswordAccountZod = IBaseEntity.extend({
@@ -808,6 +812,8 @@ export enum EventField {
808
812
  SA_STATUS = 'saStatus',
809
813
  ONBOARDING_STATUS = 'onboardingStatus',
810
814
  TRANSACTION_STATUS = 'transactionStatus',
815
+ ACTIVE = 'active',
816
+ LOCKED = 'locked',
811
817
  }
812
818
 
813
819
  export enum EventName {
@@ -1528,3 +1534,19 @@ export const StringToBooleanSchema = z.preprocess(
1528
1534
  z.boolean(),
1529
1535
  );
1530
1536
  export type StringToBooleanSchema = z.infer<typeof StringToBooleanSchema>;
1537
+
1538
+ /**
1539
+ * Reusable email schema that validates email format, transforms to lowercase,
1540
+ * and includes OpenAPI metadata.
1541
+ *
1542
+ * @example
1543
+ * EmailSchema.parse('John.Doe@EXAMPLE.COM'); // returns 'john.doe@example.com'
1544
+ * EmailSchema.optional().parse(undefined); // returns undefined
1545
+ */
1546
+ export const EmailSchema = z
1547
+ .string()
1548
+ .email()
1549
+ .transform((val) => val.toLowerCase())
1550
+ .openapi({
1551
+ example: 'neil@dalmoregroup.com',
1552
+ });
@@ -30,7 +30,7 @@ export const CreateSearchRequestSchema = z.object({
30
30
  .optional(),
31
31
  })
32
32
  .optional(),
33
- tags: z.record(z.string()).optional(),
33
+ tags: z.union([z.record(z.string()), z.array(z.any())]).optional(),
34
34
  share_url: z.union([z.literal(0), z.literal(1)]).optional(),
35
35
  exact_match: z.boolean().optional(),
36
36
  });
@@ -268,7 +268,7 @@ export const GetSearchDetailsResponseSchema = z.object({
268
268
  total_matches: z.number(),
269
269
  updated_at: z.string(),
270
270
  created_at: z.string(),
271
- tags: z.record(z.string()).optional(),
271
+ tags: z.union([z.record(z.string()), z.array(z.any())]).optional(),
272
272
  labels: z
273
273
  .array(
274
274
  z.object({
@@ -310,7 +310,7 @@ export const UpdateSearchRequestSchema = z.object({
310
310
  risk_level: z.enum(['low', 'medium', 'high', 'unknown']).optional(),
311
311
  assignee_id: z.number().optional(),
312
312
  limit: z.number().int().max(100).optional(),
313
- tags: z.record(z.string()).optional(),
313
+ tags: z.union([z.record(z.string()), z.array(z.any())]).optional(),
314
314
  });
315
315
 
316
316
  export type UpdateSearchRequest = z.infer<typeof UpdateSearchRequestSchema>;
@@ -1,7 +1,11 @@
1
1
  import { z } from 'zod';
2
2
  import { extendZodWithOpenApi } from '@anatine/zod-openapi';
3
3
  import { TypeID } from 'typeid-js';
4
- import { BaseContactUsOptions, createUrlSchema } from './common.types';
4
+ import {
5
+ BaseContactUsOptions,
6
+ createUrlSchema,
7
+ EmailSchema,
8
+ } from './common.types';
5
9
  extendZodWithOpenApi(z);
6
10
 
7
11
  export const contactUsIdSchema = z.string().refine(
@@ -55,7 +59,7 @@ export const InvestorPostContactUsZod = PostContactUsZod.extend({
55
59
  export type InvestorPostContactUsZod = z.infer<typeof InvestorPostContactUsZod>;
56
60
 
57
61
  export const PublicInvestorContactUsZod = PostContactUsZod.extend({
58
- email: z.string().email().openapi({ example: 'email@example.com' }),
62
+ email: EmailSchema,
59
63
  firstName: z.string().min(1).max(100).openapi({ example: 'John' }),
60
64
  lastName: z.string().min(1).max(100).openapi({ example: 'Doe' }),
61
65
  contactOption: z.nativeEnum(InvestorContactOptions).openapi({
@@ -6,6 +6,7 @@ import {
6
6
  ComplianceReview,
7
7
  CoveredPersonsRoleType,
8
8
  CoveredPersonsStatus,
9
+ EmailSchema,
9
10
  IDType,
10
11
  IPaginationMeta,
11
12
  } from './common.types';
@@ -137,7 +138,7 @@ export const PatchCoveredPersonsZod = z
137
138
  .openapi({ example: CoveredPersonsRoleType.ACCOUNTING }),
138
139
 
139
140
  ownership: z.number().min(0).max(100).openapi({ example: 15 }).optional(),
140
- email: z.string().nullable().optional(),
141
+ email: EmailSchema.nullable().optional(),
141
142
  idType: z
142
143
  .nativeEnum(IDType)
143
144
  .optional()
@@ -1,6 +1,6 @@
1
1
  import { extendZodWithOpenApi } from '@anatine/zod-openapi';
2
2
  import { z } from 'zod';
3
- import { AccountZod, IPaginationMeta } from './common.types';
3
+ import { AccountZod, EmailSchema, IPaginationMeta } from './common.types';
4
4
  import { IBaseEntity } from './entity.types';
5
5
  import { TypeID } from 'typeid-js';
6
6
  import { accountIdSchema } from './account.types';
@@ -43,7 +43,7 @@ export const PostEscrowAccount = z.object({
43
43
  accountNumber: z.string().optional().nullable(),
44
44
  routingNumber: z.string().min(9).max(9).optional().nullable(),
45
45
  agentName: z.string().min(2).max(50),
46
- agentEmail: z.string().email(),
46
+ agentEmail: EmailSchema,
47
47
  });
48
48
 
49
49
  export type PostEscrowAccount = z.infer<typeof PostEscrowAccount>;
@@ -65,7 +65,7 @@ export const PatchEscrowAccount = z.object({
65
65
  accountNumber: z.string().min(10).max(18).optional().nullable().optional(),
66
66
  routingNumber: z.string().min(9).max(9).optional().nullable().optional(),
67
67
  agentName: z.string().min(2).max(50).optional(),
68
- agentEmail: z.string().email().optional(),
68
+ agentEmail: EmailSchema.optional(),
69
69
  });
70
70
 
71
71
  export type PatchEscrowAccount = z.infer<typeof PatchEscrowAccount>;
@@ -16,6 +16,7 @@ import {
16
16
  EmploymentStatus,
17
17
  SourceOfIncome,
18
18
  AMLProvider,
19
+ EmailSchema,
19
20
  } from './common.types';
20
21
  import { IBaseEntity } from './entity.types';
21
22
  import { IInvestorAccount } from './investor-account.types';
@@ -288,7 +289,7 @@ export const PostIndividualBodySchema = z
288
289
  .string()
289
290
  .length(3, 'currencyCode must be 3 digits')
290
291
  .optional(),
291
- email: z.string().email().optional(),
292
+ email: EmailSchema.optional(),
292
293
  role: z.nativeEnum(IndividualRole),
293
294
  phone: PhoneZodSchema.openapi({ example: '+12124567890' }).optional(),
294
295
  ownership: z.coerce
@@ -387,7 +388,7 @@ export const UpdateIndividualBodySchema = z
387
388
  .length(3, 'currencyCode must be 3 digits')
388
389
  .optional(),
389
390
  phone: PhoneZodSchema.openapi({ example: '+12124567890' }).optional(),
390
- email: z.string().email().optional(),
391
+ email: EmailSchema.optional(),
391
392
  ownership: z.coerce
392
393
  .number()
393
394
  .min(0, 'Ownership is less than 0')
@@ -24,6 +24,7 @@ import {
24
24
  SortBy,
25
25
  SortOrder,
26
26
  AMLProvider,
27
+ EmailSchema,
27
28
  } from './common.types';
28
29
  import { accountIdSchema } from './account.types';
29
30
  import { SaStatus, tradeIdSchema, TradeZod } from './trade.types';
@@ -131,7 +132,7 @@ export type PostClientInvestorAccountBody = z.infer<
131
132
 
132
133
  export const UpdateInvestorAccountBodySchema = z.object({
133
134
  name: z.string().optional(),
134
- email: z.string().email().optional(),
135
+ email: EmailSchema.optional(),
135
136
  });
136
137
  export type UpdateInvestorAccountBody = z.infer<
137
138
  typeof UpdateInvestorAccountBodySchema
@@ -3,7 +3,9 @@ import {
3
3
  AccountZod,
4
4
  IPaginationMeta,
5
5
  IssuerRole,
6
+ PortalType,
6
7
  UserRole,
8
+ EmailSchema,
7
9
  } from './common.types';
8
10
  import { extendZodWithOpenApi } from '@anatine/zod-openapi';
9
11
  import { TypeID } from 'typeid-js';
@@ -48,7 +50,7 @@ export const InviteWithUrl = InviteWithoutSecretZod.extend({
48
50
  export type InviteWithUrl = z.infer<typeof InviteWithUrl>;
49
51
 
50
52
  export const PostIssuerInviteZod = z.object({
51
- email: z.string().email(),
53
+ email: EmailSchema,
52
54
  role: z.nativeEnum(IssuerRole),
53
55
  });
54
56
 
@@ -131,3 +133,27 @@ export const PatchInviteForComplianceZod = PatchInviteRoleZod.extend({
131
133
  export type PatchInviteForComplianceZod = z.infer<
132
134
  typeof PatchInviteForComplianceZod
133
135
  >;
136
+
137
+ export const PostInviteZod = z.object({
138
+ email: EmailSchema,
139
+ role: z.nativeEnum(UserRole).openapi({
140
+ example: UserRole.ADMIN,
141
+ }),
142
+ accountId: z.string().optional().openapi({
143
+ example: 'account_01j5y5ghx5fg68d663j1fvy2x7',
144
+ }),
145
+ portalType: z.nativeEnum(PortalType).optional().openapi({
146
+ example: PortalType.ISSUER,
147
+ }),
148
+ });
149
+
150
+ export type PostInviteZod = z.infer<typeof PostInviteZod>;
151
+
152
+ export const CompliancePostInviteZod = z.object({
153
+ email: EmailSchema,
154
+ role: z.nativeEnum(UserRole).openapi({
155
+ example: UserRole.ADMIN,
156
+ }),
157
+ });
158
+
159
+ export type CompliancePostInviteZod = z.infer<typeof CompliancePostInviteZod>;
@@ -2,6 +2,7 @@ import { z } from 'zod';
2
2
  import { IBaseEntity } from './entity.types';
3
3
  import {
4
4
  dateSchema,
5
+ EmailSchema,
5
6
  IPaginationMeta,
6
7
  KYBStatus,
7
8
  SanctionsStatus,
@@ -138,7 +139,7 @@ export const PostLegalEntitySchema = z
138
139
  investorAccountId: investorAccountIdSchema,
139
140
  name: CompanyNameSchema,
140
141
  ein: EINSchema,
141
- email: z.string().email().optional(),
142
+ email: EmailSchema.optional(),
142
143
  companyType: CompanyTypeSchema.optional(),
143
144
  phone: PhoneZodSchema.openapi({ example: '+12124567890' }).optional(),
144
145
  dateOfIncorporation: z.lazy(() => dateSchema).optional(),
@@ -153,7 +154,7 @@ export const UpdateLegalEntitySchema = z
153
154
  id: legalEntityIdSchema.optional(),
154
155
  name: CompanyNameSchema.optional(),
155
156
  ein: EINSchema,
156
- email: z.string().email().optional(),
157
+ email: EmailSchema.optional(),
157
158
  companyType: CompanyTypeSchema.optional(),
158
159
  phone: PhoneZodSchema.openapi({ example: '+12124567890' }).optional(),
159
160
  dateOfIncorporation: z.lazy(() => dateSchema).optional(),
@@ -434,3 +434,37 @@ export type EmailThemeSetting = z.infer<typeof EmailThemeSettingZod>;
434
434
 
435
435
  export const EmailThemeSettingsZod = z.array(EmailThemeSettingZod);
436
436
  export type EmailThemeSettingsZod = z.infer<typeof EmailThemeSettingsZod>;
437
+
438
+ /**
439
+ * Response from a successful email send operation.
440
+ * Based on SendGrid SDK's ClientResponse structure.
441
+ */
442
+ export const EmailSendResponseSchema = z.object({
443
+ /** HTTP status code from SendGrid (e.g., 202 for accepted) */
444
+ statusCode: z.number(),
445
+ /** SendGrid's x-message-id header for tracking emails in their dashboard */
446
+ messageId: z.string().optional(),
447
+ /** Full response headers, available for debugging if needed */
448
+ headers: z.record(z.string(), z.unknown()).optional(),
449
+ });
450
+ export type EmailSendResponse = z.infer<typeof EmailSendResponseSchema>;
451
+
452
+ /**
453
+ * Error from a failed email send operation.
454
+ * Fields are optional because error shapes vary depending on failure type
455
+ * (network errors vs SendGrid API errors).
456
+ */
457
+ export const EmailSendErrorSchema = z.object({
458
+ /** Human-readable error message */
459
+ message: z.string(),
460
+ /** Network-level error code (e.g., 'ECONNREFUSED', 'ETIMEDOUT') */
461
+ code: z.string().optional(),
462
+ /** HTTP status code if request reached SendGrid (e.g., 400, 401, 403, 413, 500) */
463
+ statusCode: z.number().optional(),
464
+ /**
465
+ * SendGrid's error response body. Structure: { errors: [{ message, field, help, id }] }
466
+ * @see https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send#responses
467
+ */
468
+ response: z.unknown().optional(),
469
+ });
470
+ export type EmailSendError = z.infer<typeof EmailSendErrorSchema>;
@@ -79,7 +79,7 @@ export const PostNoteBody = z.object({
79
79
  export type PostNoteBody = z.infer<typeof PostNoteBody>;
80
80
 
81
81
  export const CompliancePostNoteBody = PostNoteBody.extend({
82
- accountId: accountIdSchema,
82
+ accountId: accountIdSchema.nullable().default(null),
83
83
  });
84
84
 
85
85
  export type CompliancePostNoteBody = z.infer<typeof CompliancePostNoteBody>;
@@ -208,6 +208,16 @@ export type EmailNotificationPayload = z.infer<
208
208
  typeof EmailNotificationPayloadSchema
209
209
  >;
210
210
 
211
+ /**
212
+ * Payload for Slack notifications sent via Incoming Webhooks.
213
+ *
214
+ * @property webhookUrl - Slack Incoming Webhook URL
215
+ * @property channelEmail - Slack channel email integration (alternative delivery method)
216
+ * @property message - Plain text message (also serves as fallback for notifications)
217
+ * @property blocks - Optional Slack Block Kit elements for rich message formatting.
218
+ * Blocks allow structured layouts with headers, sections, images, buttons, etc.
219
+ * @see https://docs.slack.dev/messaging/creating-interactive-messages
220
+ */
211
221
  export const SlackNotificationPayloadSchema = z.object({
212
222
  webhookUrl: z.string().url().optional(),
213
223
  channelEmail: z.string().email().optional(),
@@ -3,6 +3,7 @@ import { z } from 'zod';
3
3
  import { fileIdSchema } from './file.types';
4
4
  import {
5
5
  AccountZod,
6
+ EmailSchema,
6
7
  HexCodeColorSchema,
7
8
  IPaginationMeta,
8
9
  SubdomainSchema,
@@ -462,7 +463,7 @@ export const GetSenderEmailZod = z.object({
462
463
  export type GetSenderEmailZod = z.infer<typeof GetSenderEmailZod>;
463
464
 
464
465
  export const PatchSenderEmailZod = z.object({
465
- senderEmail: z.string().email().openapi({ example: 'example@example.com' }),
466
+ senderEmail: EmailSchema,
466
467
  });
467
468
  export type PatchSenderEmailZod = z.infer<typeof PatchSenderEmailZod>;
468
469
 
@@ -21,13 +21,15 @@ import {
21
21
  createDateSchema,
22
22
  AccountStatus,
23
23
  SavedQuery,
24
+ AccountZod,
24
25
  } from './common.types';
25
- import { offeringIdSchema } from './offering.types';
26
+ import { IOffering, offeringIdSchema } from './offering.types';
26
27
  import { IBaseEntity } from './entity.types';
27
28
  import { extendZodWithOpenApi } from '@anatine/zod-openapi';
28
29
  import { TypeID } from 'typeid-js';
29
30
  import {
30
31
  paymentMethodIdSchema,
32
+ PaymentMethodResponse,
31
33
  PaymentMethodType,
32
34
  } from './payment-methods.types';
33
35
  import {
@@ -35,6 +37,7 @@ import {
35
37
  InvestorAccountExportFilters,
36
38
  ComplianceInvestorAccountExportFilters,
37
39
  RegisteredInvestorUserRawZod,
40
+ IInvestorAccount,
38
41
  } from './investor-account.types';
39
42
  import {
40
43
  tradeLineItemIdSchema,
@@ -132,6 +135,7 @@ export const CheckResultsSchema = z.object({
132
135
  export type CheckResults = z.infer<typeof CheckResultsSchema>;
133
136
 
134
137
  export const TradeIdPrefix = 'trade';
138
+ export const TradeSnapshotIdPrefix = 'trade_snapshot';
135
139
 
136
140
  export const tradeIdSchema = z.string().refine(
137
141
  (value) => {
@@ -170,6 +174,21 @@ export const tradeIdOrTidSchema = z.union([
170
174
  .openapi({ example: 'tid_00041061050r3gg28a1c60t3gf' }),
171
175
  ]);
172
176
 
177
+ export const tradeSnapshotIdSchema = z.string().refine(
178
+ (value) => {
179
+ try {
180
+ const tid = TypeID.fromString(value);
181
+ return tid.getType() === TradeSnapshotIdPrefix;
182
+ } catch {
183
+ return false;
184
+ }
185
+ },
186
+ {
187
+ message:
188
+ 'Invalid trade snapshot ID format. Must be a valid TypeID with "trade_snapshot" prefix. ex: trade_snapshot_00041061050r3gg28a1c60t3gf',
189
+ },
190
+ );
191
+
173
192
  export enum SaStatus {
174
193
  PENDING = BaseStatus.PENDING,
175
194
  SIGNED = BaseStatus.SIGNED,
@@ -274,9 +293,22 @@ export type TradeBalanceResultZod = z.infer<typeof TradeBalanceResultZod>;
274
293
 
275
294
  export const TradeZod = IBaseEntity.extend({
276
295
  investorAccountId: z.lazy(() => investorAccountIdSchema.nullable()),
296
+ investorAccount: z
297
+ .lazy(() => IInvestorAccount)
298
+ .optional()
299
+ .nullable(),
300
+ offering: z
301
+ .lazy(() => IOffering)
302
+ .optional()
303
+ .nullable(),
277
304
  accountId: accountIdSchema.nullable(),
305
+ account: z.lazy(() => AccountZod).nullable(),
278
306
  offeringId: z.lazy(() => offeringIdSchema.nullable()),
279
307
  paymentMethodId: z.lazy(() => paymentMethodIdSchema).nullable(),
308
+ paymentMethod: z
309
+ .lazy(() => PaymentMethodResponse)
310
+ .optional()
311
+ .nullable(),
280
312
  userId: z.lazy(() => userIdSchema.nullable()),
281
313
  tradeNumber: z.string(),
282
314
  ip: z.string().nullable(),
@@ -342,6 +374,21 @@ export const TradeZod = IBaseEntity.extend({
342
374
  });
343
375
  export type TradeZod = z.infer<typeof TradeZod>;
344
376
 
377
+ export enum SnapshotEvent {
378
+ COMPLIANCE_APPROVED = 'COMPLIANCE_APPROVED',
379
+ COMPLIANCE_REJECTED = 'COMPLIANCE_REJECTED',
380
+ CANCELLED = 'CANCELLED',
381
+ PLACED = 'PLACED',
382
+ SETTLED = 'SETTLED',
383
+ }
384
+
385
+ export const GetTradeSnapshotEventsResponse = z.object({
386
+ events: z.array(z.nativeEnum(SnapshotEvent)),
387
+ });
388
+ export type GetTradeSnapshotEventsResponse = z.infer<
389
+ typeof GetTradeSnapshotEventsResponse
390
+ >;
391
+
345
392
  export const IPaginatedTrade = z.object({
346
393
  items: z.array(TradeZod),
347
394
  meta: IPaginationMeta,
@@ -424,6 +471,7 @@ export const TradeFiltersZod = z.object({
424
471
  .openapi({
425
472
  example: 'issuer_01jfw4q6qef30s6fpqtsxw94ya',
426
473
  }),
474
+ snapshotEvent: z.nativeEnum(SnapshotEvent).optional(),
427
475
  offeringType: z.nativeEnum(OfferingType).optional(),
428
476
  managedBy: z.nativeEnum(ManagedByType).optional(),
429
477
  platform: z.nativeEnum(Platforms).optional(),