@soledgic/sdk 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 ADDED
@@ -0,0 +1,2227 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AuthenticationError: () => AuthenticationError,
24
+ ConflictError: () => ConflictError,
25
+ DEFAULT_API_VERSION: () => DEFAULT_API_VERSION,
26
+ DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
27
+ NotFoundError: () => NotFoundError,
28
+ Soledgic: () => Soledgic,
29
+ SoledgicError: () => SoledgicError,
30
+ ValidationError: () => ValidationError,
31
+ default: () => client_default,
32
+ hmacHex: () => hmacHex,
33
+ isArrayBufferView: () => isArrayBufferView,
34
+ mapWebhookDelivery: () => mapWebhookDelivery,
35
+ mapWebhookEndpoint: () => mapWebhookEndpoint,
36
+ parseWebhookEvent: () => parseWebhookEvent,
37
+ parseWebhookSignatureHeader: () => parseWebhookSignatureHeader,
38
+ resolveWebhookEndpointUrl: () => resolveWebhookEndpointUrl,
39
+ timingSafeEqual: () => timingSafeEqual,
40
+ verifyWebhookSignature: () => verifyWebhookSignature,
41
+ webhookPayloadToString: () => webhookPayloadToString
42
+ });
43
+ module.exports = __toCommonJS(index_exports);
44
+
45
+ // src/errors.ts
46
+ var SoledgicError = class extends Error {
47
+ constructor(message, status, details, code) {
48
+ super(message);
49
+ this.status = status;
50
+ this.details = details;
51
+ this.code = code;
52
+ this.name = "SoledgicError";
53
+ }
54
+ };
55
+ var ValidationError = class extends SoledgicError {
56
+ constructor(message, details, code = "VALIDATION_ERROR") {
57
+ super(message, 400, details, code);
58
+ this.name = "ValidationError";
59
+ }
60
+ };
61
+ var AuthenticationError = class extends SoledgicError {
62
+ constructor(message = "Invalid API key", details, code = "AUTHENTICATION_ERROR") {
63
+ super(message, 401, details, code);
64
+ this.name = "AuthenticationError";
65
+ }
66
+ };
67
+ var NotFoundError = class extends SoledgicError {
68
+ constructor(message, details, code = "NOT_FOUND") {
69
+ super(message, 404, details, code);
70
+ this.name = "NotFoundError";
71
+ }
72
+ };
73
+ var ConflictError = class extends SoledgicError {
74
+ constructor(message, details, code = "CONFLICT") {
75
+ super(message, 409, details, code);
76
+ this.name = "ConflictError";
77
+ }
78
+ };
79
+
80
+ // src/webhooks.ts
81
+ function isArrayBufferView(value) {
82
+ return typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView(value);
83
+ }
84
+ function webhookPayloadToString(payload) {
85
+ if (typeof payload === "string") {
86
+ return payload;
87
+ }
88
+ if (payload instanceof ArrayBuffer) {
89
+ return new TextDecoder().decode(new Uint8Array(payload));
90
+ }
91
+ if (isArrayBufferView(payload)) {
92
+ return new TextDecoder().decode(payload);
93
+ }
94
+ return JSON.stringify(payload);
95
+ }
96
+ function timingSafeEqual(a, b) {
97
+ const aLen = a.length;
98
+ const bLen = b.length;
99
+ const maxLen = Math.max(aLen, bLen);
100
+ let result = aLen ^ bLen;
101
+ for (let i = 0; i < maxLen; i++) {
102
+ const aChar = i < aLen ? a.charCodeAt(i) : 0;
103
+ const bChar = i < bLen ? b.charCodeAt(i) : 0;
104
+ result |= aChar ^ bChar;
105
+ }
106
+ return result === 0;
107
+ }
108
+ async function hmacHex(secret, payload) {
109
+ if (!globalThis.crypto?.subtle) {
110
+ throw new Error("Web Crypto API is not available in this runtime");
111
+ }
112
+ const key = await globalThis.crypto.subtle.importKey(
113
+ "raw",
114
+ new TextEncoder().encode(secret),
115
+ { name: "HMAC", hash: "SHA-256" },
116
+ false,
117
+ ["sign"]
118
+ );
119
+ const signature = await globalThis.crypto.subtle.sign("HMAC", key, new TextEncoder().encode(payload));
120
+ return Array.from(new Uint8Array(signature)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
121
+ }
122
+ function parseWebhookSignatureHeader(signatureHeader) {
123
+ if (!signatureHeader) {
124
+ return { timestamp: null, v1Signatures: [] };
125
+ }
126
+ let timestamp = null;
127
+ const v1Signatures = [];
128
+ for (const part of signatureHeader.split(",")) {
129
+ const [key, value] = part.trim().split("=");
130
+ if (!key || !value) continue;
131
+ if (key === "t") {
132
+ const numeric = Number(value);
133
+ timestamp = Number.isFinite(numeric) ? numeric : null;
134
+ } else if (key === "v1") {
135
+ v1Signatures.push(value);
136
+ }
137
+ }
138
+ return { timestamp, v1Signatures };
139
+ }
140
+ function toEpochSeconds(value) {
141
+ if (value instanceof Date) {
142
+ return Math.floor(value.getTime() / 1e3);
143
+ }
144
+ if (typeof value === "number" && Number.isFinite(value)) {
145
+ return Math.floor(value);
146
+ }
147
+ return Math.floor(Date.now() / 1e3);
148
+ }
149
+ async function verifyWebhookSignature(payload, signatureHeader, secret, options = {}) {
150
+ const payloadString = webhookPayloadToString(payload);
151
+ const parsed = parseWebhookSignatureHeader(signatureHeader);
152
+ if (parsed.timestamp === null || parsed.v1Signatures.length === 0) {
153
+ return false;
154
+ }
155
+ const toleranceSeconds = options.toleranceSeconds ?? 300;
156
+ if (toleranceSeconds > 0) {
157
+ const nowSeconds = toEpochSeconds(options.now);
158
+ if (Math.abs(nowSeconds - parsed.timestamp) > toleranceSeconds) {
159
+ return false;
160
+ }
161
+ }
162
+ const expected = await hmacHex(secret, `${parsed.timestamp}.${payloadString}`);
163
+ return parsed.v1Signatures.some((signature) => timingSafeEqual(signature, expected));
164
+ }
165
+ function parseWebhookEvent(payload) {
166
+ const payloadString = webhookPayloadToString(payload);
167
+ const parsed = JSON.parse(payloadString);
168
+ const type = typeof parsed.type === "string" ? parsed.type : typeof parsed.event === "string" ? parsed.event : "unknown";
169
+ return {
170
+ id: typeof parsed.id === "string" ? parsed.id : null,
171
+ type,
172
+ createdAt: typeof parsed.created_at === "string" ? parsed.created_at : null,
173
+ livemode: typeof parsed.livemode === "boolean" ? parsed.livemode : null,
174
+ data: parsed.data ?? null,
175
+ raw: parsed
176
+ };
177
+ }
178
+
179
+ // src/helpers.ts
180
+ function mapWebhookEndpoint(endpoint) {
181
+ return {
182
+ id: String(endpoint?.id ?? ""),
183
+ url: typeof endpoint?.url === "string" ? endpoint.url : "",
184
+ description: typeof endpoint?.description === "string" ? endpoint.description : null,
185
+ events: Array.isArray(endpoint?.events) ? endpoint.events.filter((event) => typeof event === "string") : [],
186
+ isActive: Boolean(endpoint?.is_active),
187
+ createdAt: typeof endpoint?.created_at === "string" ? endpoint.created_at : "",
188
+ secretRotatedAt: typeof endpoint?.secret_rotated_at === "string" ? endpoint.secret_rotated_at : null
189
+ };
190
+ }
191
+ function resolveWebhookEndpointUrl(webhookEndpoints, endpointUrl) {
192
+ if (typeof endpointUrl === "string") {
193
+ return endpointUrl;
194
+ }
195
+ if (Array.isArray(webhookEndpoints)) {
196
+ const first = webhookEndpoints[0];
197
+ return typeof first?.url === "string" ? first.url : null;
198
+ }
199
+ if (webhookEndpoints && typeof webhookEndpoints === "object" && typeof webhookEndpoints.url === "string") {
200
+ return webhookEndpoints.url;
201
+ }
202
+ return null;
203
+ }
204
+ function mapWebhookDelivery(delivery) {
205
+ return {
206
+ id: String(delivery?.id ?? ""),
207
+ endpointId: typeof delivery?.endpoint_id === "string" ? delivery.endpoint_id : null,
208
+ endpointUrl: resolveWebhookEndpointUrl(delivery?.webhook_endpoints, delivery?.endpoint_url),
209
+ eventType: typeof delivery?.event_type === "string" ? delivery.event_type : "unknown",
210
+ status: typeof delivery?.status === "string" ? delivery.status : "unknown",
211
+ attempts: Number(delivery?.attempts || 0),
212
+ maxAttempts: typeof delivery?.max_attempts === "number" ? delivery.max_attempts : null,
213
+ responseStatus: typeof delivery?.response_status === "number" ? delivery.response_status : null,
214
+ responseBody: typeof delivery?.response_body === "string" ? delivery.response_body : null,
215
+ responseTimeMs: typeof delivery?.response_time_ms === "number" ? delivery.response_time_ms : null,
216
+ createdAt: typeof delivery?.created_at === "string" ? delivery.created_at : "",
217
+ deliveredAt: typeof delivery?.delivered_at === "string" ? delivery.delivered_at : null,
218
+ nextRetryAt: typeof delivery?.next_retry_at === "string" ? delivery.next_retry_at : null,
219
+ payload: delivery?.payload && typeof delivery.payload === "object" ? delivery.payload : null
220
+ };
221
+ }
222
+
223
+ // src/client.ts
224
+ var DEFAULT_API_VERSION = "2026-03-01";
225
+ var DEFAULT_BASE_URL = "https://api.soledgic.com/v1";
226
+ var Soledgic = class {
227
+ constructor(config) {
228
+ this.webhooks = {
229
+ verifySignature: (payload, signatureHeader, secret, options) => verifyWebhookSignature(payload, signatureHeader, secret, options),
230
+ parseEvent: (payload) => parseWebhookEvent(payload)
231
+ };
232
+ if (!config.apiKey) {
233
+ throw new Error("apiKey is required");
234
+ }
235
+ let key = config.apiKey;
236
+ this._getKey = () => {
237
+ if (!key) throw new Error("Client has been destroyed");
238
+ return key;
239
+ };
240
+ this._destroyKey = () => {
241
+ key = null;
242
+ };
243
+ this.baseUrl = (config.baseUrl?.trim() || DEFAULT_BASE_URL).replace(/\/$/, "");
244
+ this.timeoutMs = config.timeout ?? 3e4;
245
+ this.apiVersion = (config.apiVersion || "").trim() || DEFAULT_API_VERSION;
246
+ }
247
+ /** Clear the API key from memory. After calling destroy(), all requests will throw. */
248
+ destroy() {
249
+ this._destroyKey?.();
250
+ }
251
+ throwTypedError(message, status, data) {
252
+ const apiCode = typeof data?.error_code === "string" ? data.error_code : typeof data?.code === "string" ? data.code : void 0;
253
+ switch (status) {
254
+ case 400:
255
+ throw new ValidationError(message, data, apiCode);
256
+ case 401:
257
+ throw new AuthenticationError(message, data, apiCode);
258
+ case 404:
259
+ throw new NotFoundError(message, data, apiCode);
260
+ case 409:
261
+ throw new ConflictError(message, data, apiCode);
262
+ default:
263
+ throw new SoledgicError(message, status, data, apiCode);
264
+ }
265
+ }
266
+ async request(endpoint, body) {
267
+ const controller = new AbortController();
268
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
269
+ try {
270
+ const response = await fetch(`${this.baseUrl}/${endpoint}`, {
271
+ method: "POST",
272
+ headers: {
273
+ "x-api-key": this._getKey(),
274
+ "Content-Type": "application/json",
275
+ "Soledgic-Version": this.apiVersion
276
+ },
277
+ body: JSON.stringify(body),
278
+ signal: controller.signal
279
+ });
280
+ const data = await response.json();
281
+ if (!response.ok) {
282
+ this.throwTypedError(
283
+ data.error || `Request failed: ${response.status}`,
284
+ response.status,
285
+ data
286
+ );
287
+ }
288
+ return data;
289
+ } finally {
290
+ clearTimeout(timer);
291
+ }
292
+ }
293
+ async requestGet(endpoint, params) {
294
+ const url = new URL(`${this.baseUrl}/${endpoint}`);
295
+ if (params) {
296
+ for (const [key, value] of Object.entries(params)) {
297
+ if (value !== void 0) url.searchParams.set(key, String(value));
298
+ }
299
+ }
300
+ const controller = new AbortController();
301
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
302
+ try {
303
+ const response = await fetch(url.toString(), {
304
+ method: "GET",
305
+ headers: {
306
+ "x-api-key": this._getKey(),
307
+ "Soledgic-Version": this.apiVersion
308
+ },
309
+ signal: controller.signal
310
+ });
311
+ const data = await response.json();
312
+ if (!response.ok) {
313
+ this.throwTypedError(
314
+ data.error || `Request failed: ${response.status}`,
315
+ response.status,
316
+ data
317
+ );
318
+ }
319
+ return data;
320
+ } finally {
321
+ clearTimeout(timer);
322
+ }
323
+ }
324
+ async requestRaw(endpoint, body) {
325
+ const controller = new AbortController();
326
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
327
+ try {
328
+ const response = await fetch(`${this.baseUrl}/${endpoint}`, {
329
+ method: "POST",
330
+ headers: {
331
+ "x-api-key": this._getKey(),
332
+ "Content-Type": "application/json",
333
+ "Soledgic-Version": this.apiVersion
334
+ },
335
+ body: JSON.stringify(body),
336
+ signal: controller.signal
337
+ });
338
+ if (!response.ok) {
339
+ const text = await response.text();
340
+ let parsed;
341
+ try {
342
+ parsed = JSON.parse(text);
343
+ } catch {
344
+ parsed = { error: text };
345
+ }
346
+ this.throwTypedError(
347
+ parsed.error || `Request failed: ${response.status}`,
348
+ response.status,
349
+ parsed
350
+ );
351
+ }
352
+ return response;
353
+ } finally {
354
+ clearTimeout(timer);
355
+ }
356
+ }
357
+ async requestGetRaw(endpoint, params) {
358
+ const url = new URL(`${this.baseUrl}/${endpoint}`);
359
+ if (params) {
360
+ for (const [key, value] of Object.entries(params)) {
361
+ if (value !== void 0) url.searchParams.set(key, String(value));
362
+ }
363
+ }
364
+ const controller = new AbortController();
365
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
366
+ try {
367
+ const response = await fetch(url.toString(), {
368
+ method: "GET",
369
+ headers: {
370
+ "x-api-key": this._getKey(),
371
+ "Soledgic-Version": this.apiVersion
372
+ },
373
+ signal: controller.signal
374
+ });
375
+ if (!response.ok) {
376
+ const text = await response.text();
377
+ let parsed;
378
+ try {
379
+ parsed = JSON.parse(text);
380
+ } catch {
381
+ parsed = { error: text };
382
+ }
383
+ this.throwTypedError(
384
+ parsed.error || `Request failed: ${response.status}`,
385
+ response.status,
386
+ parsed
387
+ );
388
+ }
389
+ return response;
390
+ } finally {
391
+ clearTimeout(timer);
392
+ }
393
+ }
394
+ async requestDelete(endpoint) {
395
+ const controller = new AbortController();
396
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
397
+ try {
398
+ const response = await fetch(`${this.baseUrl}/${endpoint}`, {
399
+ method: "DELETE",
400
+ headers: {
401
+ "x-api-key": this._getKey(),
402
+ "Soledgic-Version": this.apiVersion
403
+ },
404
+ signal: controller.signal
405
+ });
406
+ const data = await response.json();
407
+ if (!response.ok) {
408
+ this.throwTypedError(
409
+ data.error || `Request failed: ${response.status}`,
410
+ response.status,
411
+ data
412
+ );
413
+ }
414
+ return data;
415
+ } finally {
416
+ clearTimeout(timer);
417
+ }
418
+ }
419
+ // === STANDARD MODE - INCOME & EXPENSES ===
420
+ async recordIncome(req) {
421
+ return this.request("record-income", {
422
+ reference_id: req.referenceId,
423
+ amount: req.amount,
424
+ description: req.description,
425
+ category: req.category,
426
+ customer_id: req.customerId,
427
+ customer_name: req.customerName,
428
+ received_to: req.receivedTo,
429
+ invoice_id: req.invoiceId,
430
+ transaction_date: req.transactionDate,
431
+ metadata: req.metadata
432
+ });
433
+ }
434
+ async recordExpense(req) {
435
+ return this.request("record-expense", {
436
+ reference_id: req.referenceId,
437
+ amount: req.amount,
438
+ description: req.description,
439
+ category: req.category,
440
+ vendor_id: req.vendorId,
441
+ vendor_name: req.vendorName,
442
+ paid_from: req.paidFrom,
443
+ receipt_url: req.receiptUrl,
444
+ tax_deductible: req.taxDeductible,
445
+ transaction_date: req.transactionDate,
446
+ metadata: req.metadata,
447
+ authorizing_instrument_id: req.authorizingInstrumentId,
448
+ risk_evaluation_id: req.riskEvaluationId,
449
+ authorization_decision_id: req.authorizationDecisionId
450
+ });
451
+ }
452
+ async recordBill(req) {
453
+ return this.request("record-bill", {
454
+ amount: req.amount,
455
+ description: req.description,
456
+ vendor_name: req.vendorName,
457
+ vendor_id: req.vendorId,
458
+ reference_id: req.referenceId,
459
+ due_date: req.dueDate,
460
+ expense_category: req.expenseCategory,
461
+ paid: req.paid,
462
+ metadata: req.metadata,
463
+ authorizing_instrument_id: req.authorizingInstrumentId,
464
+ risk_evaluation_id: req.riskEvaluationId,
465
+ authorization_decision_id: req.authorizationDecisionId
466
+ });
467
+ }
468
+ // === AUTHORIZING INSTRUMENTS ===
469
+ // Register financial authorization instruments for transaction validation
470
+ // Instruments are immutable and ledger-adjacent - they explain WHY money moved
471
+ async registerInstrument(req) {
472
+ return this.request("register-instrument", {
473
+ external_ref: req.externalRef,
474
+ extracted_terms: {
475
+ amount: req.extractedTerms.amount,
476
+ currency: req.extractedTerms.currency,
477
+ cadence: req.extractedTerms.cadence,
478
+ counterparty_name: req.extractedTerms.counterpartyName
479
+ }
480
+ });
481
+ }
482
+ // === SHADOW LEDGER (GHOST ENTRIES) ===
483
+ // Project future obligations based on authorizing instrument terms.
484
+ // Ghost entries NEVER affect balances or entries - only express future intent.
485
+ async projectIntent(req) {
486
+ const response = await this.request("project-intent", {
487
+ authorizing_instrument_id: req.authorizingInstrumentId,
488
+ until_date: req.untilDate,
489
+ horizon_count: req.horizonCount
490
+ });
491
+ return {
492
+ success: response.success,
493
+ instrumentId: response.instrument_id,
494
+ externalRef: response.external_ref,
495
+ cadence: response.cadence,
496
+ projectionsCreated: response.projections_created,
497
+ projectionsRequested: response.projections_requested,
498
+ duplicatesSkipped: response.duplicates_skipped,
499
+ dateRange: response.date_range,
500
+ projectedDates: response.projected_dates
501
+ };
502
+ }
503
+ // === REVERSALS & CORRECTIONS ===
504
+ async reverseTransaction(req) {
505
+ const response = await this.request("reverse-transaction", {
506
+ transaction_id: req.transactionId,
507
+ reason: req.reason,
508
+ partial_amount: req.partialAmount,
509
+ idempotency_key: req.idempotencyKey,
510
+ metadata: req.metadata
511
+ });
512
+ return {
513
+ success: response.success,
514
+ voidType: response.void_type,
515
+ message: response.message,
516
+ transactionId: response.transaction_id ?? response.original_transaction_id ?? req.transactionId,
517
+ reversalId: response.reversal_id ?? null,
518
+ reversedAmount: response.reversed_amount ?? null,
519
+ isPartial: response.is_partial ?? null,
520
+ voidedAt: response.voided_at ?? null,
521
+ reversedAt: response.reversed_at ?? null,
522
+ warning: response.warning ?? null
523
+ };
524
+ }
525
+ // === PERIOD MANAGEMENT ===
526
+ async listPeriods() {
527
+ return this.request("close-period", { action: "list" });
528
+ }
529
+ async createPeriod(req) {
530
+ return this.request("close-period", {
531
+ action: "create",
532
+ start_date: req.startDate,
533
+ end_date: req.endDate,
534
+ name: req.name
535
+ });
536
+ }
537
+ async closePeriod(year, month, quarter) {
538
+ return this.request("close-period", { year, month, quarter });
539
+ }
540
+ // === RECONCILIATION ===
541
+ async matchTransaction(req) {
542
+ const response = await this.request("reconciliations/matches", {
543
+ transaction_id: req.transactionId,
544
+ bank_transaction_id: req.bankTransactionId
545
+ });
546
+ return {
547
+ success: response.success,
548
+ match: {
549
+ id: response.match.id,
550
+ transactionId: response.match.transaction_id,
551
+ bankTransactionId: response.match.bank_transaction_id,
552
+ status: response.match.status,
553
+ matchedAt: response.match.matched_at
554
+ }
555
+ };
556
+ }
557
+ async unmatchTransaction(transactionId) {
558
+ const response = await this.requestDelete(`reconciliations/matches/${transactionId}`);
559
+ return {
560
+ success: response.success,
561
+ deleted: Boolean(response.deleted),
562
+ transactionId: response.transaction_id
563
+ };
564
+ }
565
+ async listUnmatchedTransactions() {
566
+ const response = await this.requestGet("reconciliations/unmatched");
567
+ return {
568
+ success: response.success,
569
+ unmatchedCount: response.unmatched_count ?? 0,
570
+ transactions: (response.transactions || []).map((transaction) => ({
571
+ id: transaction.id,
572
+ referenceId: transaction.reference_id ?? null,
573
+ description: transaction.description ?? null,
574
+ amount: transaction.amount,
575
+ currency: transaction.currency || "USD",
576
+ createdAt: transaction.created_at,
577
+ status: transaction.status,
578
+ metadata: transaction.metadata || {}
579
+ }))
580
+ };
581
+ }
582
+ async createReconciliationSnapshot(req) {
583
+ const response = await this.request("reconciliations/snapshots", {
584
+ period_id: req.periodId,
585
+ as_of_date: req.asOfDate
586
+ });
587
+ return {
588
+ success: response.success,
589
+ snapshot_id: response.snapshot.id,
590
+ integrity_hash: response.snapshot.integrity_hash
591
+ };
592
+ }
593
+ async getReconciliationSnapshot(periodId) {
594
+ const response = await this.requestGet(`reconciliations/snapshots/${periodId}`);
595
+ return {
596
+ success: response.success,
597
+ snapshot: {
598
+ id: response.snapshot.id,
599
+ periodStart: response.snapshot.period_start,
600
+ periodEnd: response.snapshot.period_end,
601
+ integrityHash: response.snapshot.integrity_hash,
602
+ integrityValid: Boolean(response.snapshot.integrity_valid),
603
+ summary: {
604
+ totalMatched: response.snapshot.summary?.total_matched ?? 0,
605
+ totalUnmatched: response.snapshot.summary?.total_unmatched ?? 0,
606
+ matchedAmount: response.snapshot.summary?.matched_amount ?? 0,
607
+ unmatchedAmount: response.snapshot.summary?.unmatched_amount ?? 0
608
+ }
609
+ }
610
+ };
611
+ }
612
+ async autoMatchBankTransaction(bankAggregatorTransactionId) {
613
+ const response = await this.request("reconciliations/auto-match", {
614
+ bank_aggregator_transaction_id: bankAggregatorTransactionId
615
+ });
616
+ return {
617
+ success: response.success,
618
+ result: {
619
+ matched: Boolean(response.result?.matched),
620
+ matchType: response.result?.match_type ?? null,
621
+ matchedTransactionId: response.result?.matched_transaction_id ?? null,
622
+ bankAggregatorTransactionId: response.result?.bank_aggregator_transaction_id ?? bankAggregatorTransactionId
623
+ }
624
+ };
625
+ }
626
+ // === FROZEN STATEMENTS ===
627
+ async generateFrozenStatements(periodId) {
628
+ return this.request("frozen-statements", {
629
+ action: "generate",
630
+ period_id: periodId
631
+ });
632
+ }
633
+ async getFrozenStatement(periodId, statementType) {
634
+ return this.request("frozen-statements", {
635
+ action: "get",
636
+ period_id: periodId,
637
+ statement_type: statementType
638
+ });
639
+ }
640
+ async listFrozenStatements(periodId) {
641
+ return this.request("frozen-statements", {
642
+ action: "list",
643
+ period_id: periodId
644
+ });
645
+ }
646
+ async verifyFrozenStatements(periodId) {
647
+ return this.request("frozen-statements", {
648
+ action: "verify",
649
+ period_id: periodId
650
+ });
651
+ }
652
+ // === SPLITS MANAGEMENT ===
653
+ async listTiers() {
654
+ return this.request("manage-splits", { action: "list_tiers" });
655
+ }
656
+ async getEffectiveSplit(creatorId) {
657
+ return this.request("manage-splits", { action: "get_effective_split", creator_id: creatorId });
658
+ }
659
+ async setCreatorSplit(creatorId, splitPercent) {
660
+ return this.request("manage-splits", { action: "set_creator_split", creator_id: creatorId, split_percent: splitPercent });
661
+ }
662
+ async clearCreatorSplit(creatorId) {
663
+ return this.request("manage-splits", { action: "clear_creator_split", creator_id: creatorId });
664
+ }
665
+ async autoPromoteCreators() {
666
+ return this.request("manage-splits", { action: "auto_promote" });
667
+ }
668
+ async getSummary() {
669
+ const response = await this.requestGet("participants");
670
+ const participants = Array.isArray(response.participants) ? response.participants : [];
671
+ const summary = participants.reduce((totals, participant) => ({
672
+ total_ledger_balance: totals.total_ledger_balance + Number(participant.ledger_balance || 0),
673
+ total_held_amount: totals.total_held_amount + Number(participant.held_amount || 0),
674
+ total_available_balance: totals.total_available_balance + Number(participant.available_balance || 0)
675
+ }), {
676
+ total_ledger_balance: 0,
677
+ total_held_amount: 0,
678
+ total_available_balance: 0
679
+ });
680
+ return {
681
+ success: response.success,
682
+ data: {
683
+ ...summary,
684
+ participant_count: participants.length
685
+ }
686
+ };
687
+ }
688
+ // === REPORTS ===
689
+ async getProfitLoss(startDate, endDate) {
690
+ return this.request("generate-report", { report_type: "profit_loss", start_date: startDate, end_date: endDate });
691
+ }
692
+ async getTrialBalance(asOf) {
693
+ return this.request("generate-report", { report_type: "trial_balance", as_of: asOf });
694
+ }
695
+ async get1099Summary(year) {
696
+ return this.request("generate-report", { report_type: "1099_summary", tax_year: year });
697
+ }
698
+ async getCreatorEarnings(startDate, endDate) {
699
+ return this.request("generate-report", { report_type: "creator_earnings", start_date: startDate, end_date: endDate });
700
+ }
701
+ async getHistoricalEarnings(options = {}) {
702
+ return this.requestGet("earnings", {
703
+ start_date: options.startDate,
704
+ end_date: options.endDate,
705
+ creator_id: options.creatorId,
706
+ granularity: options.granularity
707
+ });
708
+ }
709
+ async getTransactions(startDate, endDate, creatorId) {
710
+ return this.request("generate-report", { report_type: "transaction_history", start_date: startDate, end_date: endDate, creator_id: creatorId });
711
+ }
712
+ // === CREDITS ===
713
+ /** Issue credits to a user. 1000 credits = $1 USD (Soledgic standard rate). */
714
+ async issueCredits(userId, credits, options = {}) {
715
+ return this.request("credits", {
716
+ action: "issue",
717
+ user_id: userId,
718
+ credits,
719
+ reason: options.reason,
720
+ reference_id: options.referenceId
721
+ });
722
+ }
723
+ /** Convert earned credits to spendable balance. Minimum 5000 credits ($5). */
724
+ async convertCredits(userId, credits) {
725
+ return this.request("credits", {
726
+ action: "convert",
727
+ user_id: userId,
728
+ credits
729
+ });
730
+ }
731
+ /** Spend spendable balance on creator content. Amount in cents. Split applies. */
732
+ async redeemCredits(userId, creatorId, amountCents, referenceId, options = {}) {
733
+ return this.request("credits", {
734
+ action: "redeem",
735
+ user_id: userId,
736
+ creator_id: creatorId,
737
+ amount: amountCents,
738
+ reference_id: referenceId,
739
+ description: options.description,
740
+ split_percent: options.splitPercent
741
+ });
742
+ }
743
+ /** Get user's credit balance (unconverted) and spendable balance (converted). */
744
+ async getCreditBalance(userId) {
745
+ return this.request("credits", { action: "balance", user_id: userId });
746
+ }
747
+ // === PDF EXPORTS ===
748
+ async generatePDF(reportType, options = {}) {
749
+ return this.request("generate-pdf", {
750
+ report_type: reportType,
751
+ creator_id: options.creatorId,
752
+ start_date: options.startDate,
753
+ end_date: options.endDate,
754
+ tax_year: options.taxYear,
755
+ period_id: options.periodId
756
+ });
757
+ }
758
+ async getCreatorStatement(creatorId, startDate, endDate) {
759
+ return this.generatePDF("creator_statement", { creatorId, startDate, endDate });
760
+ }
761
+ async getProfitLossPDF(startDate, endDate, periodId) {
762
+ return this.generatePDF("profit_loss", { startDate, endDate, periodId });
763
+ }
764
+ async getTrialBalancePDF() {
765
+ return this.generatePDF("trial_balance", {});
766
+ }
767
+ async get1099PDF(taxYear) {
768
+ return this.generatePDF("1099", { taxYear });
769
+ }
770
+ // === AUTO-EMAIL ===
771
+ async configureEmail(config) {
772
+ return this.request("send-statements", {
773
+ action: "configure",
774
+ email_config: {
775
+ enabled: config.enabled,
776
+ send_day: config.sendDay || 1,
777
+ from_name: config.fromName,
778
+ from_email: config.fromEmail,
779
+ subject_template: config.subjectTemplate,
780
+ body_template: config.bodyTemplate,
781
+ cc_admin: config.ccAdmin,
782
+ admin_email: config.adminEmail
783
+ }
784
+ });
785
+ }
786
+ async sendMonthlyStatements(year, month) {
787
+ return this.request("send-statements", {
788
+ action: "send_monthly_statements",
789
+ year,
790
+ month
791
+ });
792
+ }
793
+ async sendCreatorStatement(creatorId, year, month) {
794
+ return this.request("send-statements", {
795
+ action: "send_single_statement",
796
+ creator_id: creatorId,
797
+ year,
798
+ month
799
+ });
800
+ }
801
+ async previewStatementEmail(creatorId, year, month) {
802
+ return this.request("send-statements", {
803
+ action: "preview",
804
+ creator_id: creatorId,
805
+ year,
806
+ month
807
+ });
808
+ }
809
+ async getEmailHistory() {
810
+ return this.request("send-statements", { action: "get_queue" });
811
+ }
812
+ // === WEBHOOKS ===
813
+ async listWebhookEndpoints() {
814
+ const response = await this.request("webhooks", { action: "list" });
815
+ return {
816
+ success: response.success,
817
+ data: Array.isArray(response.data) ? response.data.map(mapWebhookEndpoint) : []
818
+ };
819
+ }
820
+ async createWebhookEndpoint(config) {
821
+ const response = await this.request("webhooks", {
822
+ action: "create",
823
+ url: config.url,
824
+ description: config.description,
825
+ events: config.events || ["*"]
826
+ });
827
+ return {
828
+ success: response.success,
829
+ data: {
830
+ ...mapWebhookEndpoint(response.data || {}),
831
+ secret: typeof response.data?.secret === "string" ? response.data.secret : null
832
+ },
833
+ message: typeof response.message === "string" ? response.message : void 0
834
+ };
835
+ }
836
+ async updateWebhookEndpoint(endpointId, updates) {
837
+ const response = await this.request("webhooks", {
838
+ action: "update",
839
+ endpoint_id: endpointId,
840
+ url: updates.url,
841
+ description: updates.description,
842
+ events: updates.events,
843
+ is_active: updates.isActive
844
+ });
845
+ return {
846
+ success: response.success,
847
+ data: mapWebhookEndpoint(response.data || {})
848
+ };
849
+ }
850
+ async deleteWebhookEndpoint(endpointId) {
851
+ const response = await this.request("webhooks", { action: "delete", endpoint_id: endpointId });
852
+ return {
853
+ success: response.success,
854
+ message: typeof response.message === "string" ? response.message : void 0
855
+ };
856
+ }
857
+ async testWebhookEndpoint(endpointId) {
858
+ const response = await this.request("webhooks", { action: "test", endpoint_id: endpointId });
859
+ return {
860
+ success: response.success,
861
+ error: typeof response.error === "string" ? response.error : void 0,
862
+ data: {
863
+ delivered: Boolean(response.data?.delivered),
864
+ status: typeof response.data?.status === "number" ? response.data.status : null,
865
+ responseTimeMs: typeof response.data?.response_time_ms === "number" ? response.data.response_time_ms : null
866
+ }
867
+ };
868
+ }
869
+ async getWebhookDeliveries(endpointId, limit) {
870
+ const response = await this.request("webhooks", {
871
+ action: "deliveries",
872
+ endpoint_id: endpointId,
873
+ limit
874
+ });
875
+ return {
876
+ success: response.success,
877
+ data: Array.isArray(response.data) ? response.data.map(mapWebhookDelivery) : []
878
+ };
879
+ }
880
+ async retryWebhookDelivery(deliveryId) {
881
+ const response = await this.request("webhooks", { action: "retry", delivery_id: deliveryId });
882
+ return {
883
+ success: response.success,
884
+ message: typeof response.message === "string" ? response.message : void 0
885
+ };
886
+ }
887
+ async rotateWebhookSecret(endpointId) {
888
+ const response = await this.request("webhooks", {
889
+ action: "rotate_secret",
890
+ endpoint_id: endpointId
891
+ });
892
+ return {
893
+ success: response.success,
894
+ data: {
895
+ secret: typeof response.data?.secret === "string" ? response.data.secret : null
896
+ },
897
+ message: typeof response.message === "string" ? response.message : void 0
898
+ };
899
+ }
900
+ // === BREACH ALERTS ===
901
+ // Configure Slack, email, or webhook notifications for breach risk events.
902
+ // Alerts trigger when project-intent creates projections that exceed cash coverage.
903
+ async listAlerts() {
904
+ const response = await this.request("configure-alerts", { action: "list" });
905
+ return {
906
+ success: response.success,
907
+ data: (response.data || []).map((c) => ({
908
+ id: c.id,
909
+ alertType: c.alert_type,
910
+ channel: c.channel,
911
+ config: c.config,
912
+ thresholds: {
913
+ coverageRatioBelow: c.thresholds?.coverage_ratio_below,
914
+ shortfallAbove: c.thresholds?.shortfall_above
915
+ },
916
+ isActive: c.is_active,
917
+ lastTriggeredAt: c.last_triggered_at,
918
+ triggerCount: c.trigger_count,
919
+ createdAt: c.created_at
920
+ }))
921
+ };
922
+ }
923
+ async createAlert(req) {
924
+ const config = {};
925
+ if ("webhookUrl" in req.config) {
926
+ config.webhook_url = req.config.webhookUrl;
927
+ config.channel = req.config.channel;
928
+ } else if ("recipients" in req.config) {
929
+ config.recipients = req.config.recipients;
930
+ }
931
+ const response = await this.request("configure-alerts", {
932
+ action: "create",
933
+ alert_type: req.alertType,
934
+ channel: req.channel,
935
+ config,
936
+ thresholds: req.thresholds ? {
937
+ coverage_ratio_below: req.thresholds.coverageRatioBelow,
938
+ shortfall_above: req.thresholds.shortfallAbove
939
+ } : void 0,
940
+ is_active: req.isActive
941
+ });
942
+ return {
943
+ success: response.success,
944
+ data: {
945
+ id: response.data.id,
946
+ alertType: response.data.alert_type,
947
+ channel: response.data.channel,
948
+ config: response.data.config || {},
949
+ thresholds: {
950
+ coverageRatioBelow: response.data.thresholds?.coverage_ratio_below,
951
+ shortfallAbove: response.data.thresholds?.shortfall_above
952
+ },
953
+ isActive: response.data.is_active,
954
+ triggerCount: response.data.trigger_count || 0,
955
+ createdAt: response.data.created_at
956
+ }
957
+ };
958
+ }
959
+ async updateAlert(req) {
960
+ const config = req.config ? {} : void 0;
961
+ if (req.config) {
962
+ if ("webhookUrl" in req.config && req.config.webhookUrl) {
963
+ config.webhook_url = req.config.webhookUrl;
964
+ }
965
+ if ("channel" in req.config) {
966
+ config.channel = req.config.channel;
967
+ }
968
+ if ("recipients" in req.config) {
969
+ config.recipients = req.config.recipients;
970
+ }
971
+ }
972
+ const response = await this.request("configure-alerts", {
973
+ action: "update",
974
+ config_id: req.configId,
975
+ config,
976
+ thresholds: req.thresholds ? {
977
+ coverage_ratio_below: req.thresholds.coverageRatioBelow,
978
+ shortfall_above: req.thresholds.shortfallAbove
979
+ } : void 0,
980
+ is_active: req.isActive
981
+ });
982
+ return {
983
+ success: response.success,
984
+ data: {
985
+ id: response.data.id,
986
+ alertType: response.data.alert_type,
987
+ channel: response.data.channel,
988
+ config: response.data.config || {},
989
+ thresholds: {
990
+ coverageRatioBelow: response.data.thresholds?.coverage_ratio_below,
991
+ shortfallAbove: response.data.thresholds?.shortfall_above
992
+ },
993
+ isActive: response.data.is_active,
994
+ triggerCount: response.data.trigger_count ?? 0,
995
+ createdAt: response.data.created_at ?? ""
996
+ }
997
+ };
998
+ }
999
+ async deleteAlert(configId) {
1000
+ return this.request("configure-alerts", {
1001
+ action: "delete",
1002
+ config_id: configId
1003
+ });
1004
+ }
1005
+ async testAlert(configId) {
1006
+ return this.request("configure-alerts", {
1007
+ action: "test",
1008
+ config_id: configId
1009
+ });
1010
+ }
1011
+ // === PREFLIGHT AUTHORIZATION (Phase 3) ===
1012
+ // Evaluate whether a proposed transaction should be allowed BEFORE execution.
1013
+ // This does NOT move money - only decides if the transaction is permitted.
1014
+ async preflightAuthorization(req) {
1015
+ const response = await this.request("preflight-authorization", {
1016
+ idempotency_key: req.idempotencyKey,
1017
+ amount: req.amount,
1018
+ currency: req.currency,
1019
+ counterparty_name: req.counterpartyName,
1020
+ authorizing_instrument_id: req.authorizingInstrumentId,
1021
+ expected_date: req.expectedDate,
1022
+ category: req.category
1023
+ });
1024
+ return {
1025
+ success: response.success,
1026
+ cached: response.cached,
1027
+ decision: {
1028
+ id: response.decision.id,
1029
+ decision: response.decision.decision,
1030
+ violatedPolicies: (response.decision.violated_policies || []).map((v) => ({
1031
+ policyId: v.policy_id,
1032
+ policyType: v.policy_type,
1033
+ severity: v.severity,
1034
+ reason: v.reason
1035
+ })),
1036
+ expiresAt: response.decision.expires_at,
1037
+ createdAt: response.decision.created_at
1038
+ },
1039
+ message: response.message
1040
+ };
1041
+ }
1042
+ // Convenience method: preflight check then record expense if allowed
1043
+ async preflightAndRecordExpense(preflight, expense) {
1044
+ const preflightResult = await this.preflightAuthorization(preflight);
1045
+ if (preflightResult.decision.decision === "blocked") {
1046
+ return { preflight: preflightResult };
1047
+ }
1048
+ const transaction = await this.recordExpense({
1049
+ ...expense,
1050
+ authorizationDecisionId: preflightResult.decision.id
1051
+ });
1052
+ return { preflight: preflightResult, transaction };
1053
+ }
1054
+ // Convenience method: preflight check then record bill if allowed
1055
+ async preflightAndRecordBill(preflight, bill) {
1056
+ const preflightResult = await this.preflightAuthorization(preflight);
1057
+ if (preflightResult.decision.decision === "blocked") {
1058
+ return { preflight: preflightResult };
1059
+ }
1060
+ const transaction = await this.recordBill({
1061
+ ...bill,
1062
+ authorizationDecisionId: preflightResult.decision.id
1063
+ });
1064
+ return { preflight: preflightResult, transaction };
1065
+ }
1066
+ // === BANK IMPORT ===
1067
+ async getImportTemplates() {
1068
+ return this.request("import-transactions", { action: "get_templates" });
1069
+ }
1070
+ async parseImportFile(fileBase64, format) {
1071
+ return this.request("import-transactions", {
1072
+ action: "parse_preview",
1073
+ data: fileBase64,
1074
+ format
1075
+ });
1076
+ }
1077
+ async importTransactions(transactions) {
1078
+ return this.request("import-transactions", {
1079
+ action: "import",
1080
+ transactions
1081
+ });
1082
+ }
1083
+ async saveImportTemplate(template) {
1084
+ return this.request("import-transactions", {
1085
+ action: "save_template",
1086
+ template
1087
+ });
1088
+ }
1089
+ // === ESCROW / HELD FUNDS ===
1090
+ async getEscrowSummary() {
1091
+ const response = await this.requestGet("holds/summary");
1092
+ return {
1093
+ success: response.success,
1094
+ summary: response.summary || {}
1095
+ };
1096
+ }
1097
+ async getHeldFunds(options) {
1098
+ return this.requestGet("holds", {
1099
+ venture_id: options?.ventureId,
1100
+ participant_id: options?.creatorId,
1101
+ ready_only: options?.readyOnly,
1102
+ limit: options?.limit
1103
+ });
1104
+ }
1105
+ async releaseFunds(entryId, executeTransfer = true) {
1106
+ const response = await this.request(`holds/${entryId}/release`, {
1107
+ execute_transfer: executeTransfer
1108
+ });
1109
+ return {
1110
+ success: response.success,
1111
+ release_id: response.release?.id ?? null,
1112
+ entry_id: response.release?.hold_id ?? entryId,
1113
+ executed: Boolean(response.release?.executed),
1114
+ transfer_id: response.release?.transfer_id ?? null,
1115
+ transfer_status: response.release?.transfer_status ?? null,
1116
+ amount: response.release?.amount ?? null,
1117
+ currency: response.release?.currency ?? null
1118
+ };
1119
+ }
1120
+ // === PAYOUT ELIGIBILITY ===
1121
+ async checkPayoutEligibility(participantId) {
1122
+ const response = await this.requestGet(`participants/${participantId}/payout-eligibility`);
1123
+ return {
1124
+ success: response.success,
1125
+ participant_id: response.eligibility?.participant_id ?? participantId,
1126
+ eligible: Boolean(response.eligibility?.eligible),
1127
+ available_balance: response.eligibility?.available_balance ?? 0,
1128
+ issues: response.eligibility?.issues || [],
1129
+ requirements: response.eligibility?.requirements || {}
1130
+ };
1131
+ }
1132
+ // === HEALTH CHECKS ===
1133
+ async runHealthCheck() {
1134
+ return this.request("health-check", { action: "run" });
1135
+ }
1136
+ async getHealthStatus() {
1137
+ return this.request("health-check", { action: "status" });
1138
+ }
1139
+ async getHealthHistory() {
1140
+ return this.request("health-check", { action: "history" });
1141
+ }
1142
+ // === FINANCIAL REPORTS (DETAILED) ===
1143
+ async getAPAging(asOfDate) {
1144
+ return this.requestGet("ap-aging", { as_of_date: asOfDate });
1145
+ }
1146
+ async getARAging(asOfDate) {
1147
+ return this.requestGet("ar-aging", { as_of_date: asOfDate });
1148
+ }
1149
+ async getBalanceSheet(asOfDate) {
1150
+ return this.requestGet("balance-sheet", { as_of_date: asOfDate });
1151
+ }
1152
+ async getDetailedTrialBalance(options) {
1153
+ return this.requestGet("trial-balance", {
1154
+ as_of: options?.asOf,
1155
+ snapshot: options?.snapshot ? "true" : void 0
1156
+ });
1157
+ }
1158
+ async getDetailedProfitLoss(options) {
1159
+ return this.requestGet("profit-loss", {
1160
+ year: options?.year,
1161
+ month: options?.month,
1162
+ quarter: options?.quarter,
1163
+ start_date: options?.startDate,
1164
+ end_date: options?.endDate,
1165
+ breakdown: options?.breakdown
1166
+ });
1167
+ }
1168
+ async getRunway() {
1169
+ return this.requestGet("get-runway");
1170
+ }
1171
+ // === TREASURY RESOURCES ===
1172
+ async createParticipant(req) {
1173
+ const response = await this.request("participants", {
1174
+ participant_id: req.participantId,
1175
+ user_id: req.userId,
1176
+ display_name: req.displayName,
1177
+ email: req.email,
1178
+ default_split_percent: req.defaultSplitPercent,
1179
+ tax_info: req.taxInfo ? {
1180
+ tax_id_type: req.taxInfo.taxIdType,
1181
+ tax_id_last4: req.taxInfo.taxIdLast4,
1182
+ legal_name: req.taxInfo.legalName,
1183
+ business_type: req.taxInfo.businessType,
1184
+ address: req.taxInfo.address ? {
1185
+ line1: req.taxInfo.address.line1,
1186
+ line2: req.taxInfo.address.line2,
1187
+ city: req.taxInfo.address.city,
1188
+ state: req.taxInfo.address.state,
1189
+ postal_code: req.taxInfo.address.postalCode,
1190
+ country: req.taxInfo.address.country
1191
+ } : void 0
1192
+ } : void 0,
1193
+ payout_preferences: req.payoutPreferences ? {
1194
+ schedule: req.payoutPreferences.schedule,
1195
+ minimum_amount: req.payoutPreferences.minimumAmount,
1196
+ method: req.payoutPreferences.method
1197
+ } : void 0,
1198
+ metadata: req.metadata
1199
+ });
1200
+ const participant = response.participant || {};
1201
+ return {
1202
+ success: response.success,
1203
+ participant: {
1204
+ id: participant.id,
1205
+ accountId: participant.account_id,
1206
+ linkedUserId: participant.linked_user_id ?? null,
1207
+ displayName: participant.display_name,
1208
+ email: participant.email,
1209
+ defaultSplitPercent: participant.default_split_percent,
1210
+ payoutPreferences: participant.payout_preferences || {},
1211
+ createdAt: participant.created_at
1212
+ }
1213
+ };
1214
+ }
1215
+ async listParticipants() {
1216
+ const response = await this.requestGet("participants");
1217
+ return {
1218
+ success: response.success,
1219
+ participants: (response.participants || []).map((participant) => ({
1220
+ id: participant.id,
1221
+ linkedUserId: participant.linked_user_id ?? null,
1222
+ name: participant.name ?? null,
1223
+ tier: participant.tier ?? null,
1224
+ ledgerBalance: participant.ledger_balance,
1225
+ heldAmount: participant.held_amount,
1226
+ availableBalance: participant.available_balance
1227
+ }))
1228
+ };
1229
+ }
1230
+ async getParticipant(participantId) {
1231
+ const response = await this.requestGet(`participants/${participantId}`);
1232
+ const participant = response.participant || {};
1233
+ return {
1234
+ success: response.success,
1235
+ participant: {
1236
+ id: participant.id,
1237
+ linkedUserId: participant.linked_user_id ?? null,
1238
+ name: participant.name ?? null,
1239
+ tier: participant.tier ?? null,
1240
+ customSplitPercent: participant.custom_split_percent ?? null,
1241
+ ledgerBalance: participant.ledger_balance,
1242
+ heldAmount: participant.held_amount,
1243
+ availableBalance: participant.available_balance,
1244
+ holds: (participant.holds || []).map((hold) => ({
1245
+ amount: hold.amount,
1246
+ reason: hold.reason ?? null,
1247
+ releaseDate: hold.release_date ?? null,
1248
+ status: hold.status
1249
+ }))
1250
+ }
1251
+ };
1252
+ }
1253
+ async getParticipantPayoutEligibility(participantId) {
1254
+ const response = await this.requestGet(`participants/${participantId}/payout-eligibility`);
1255
+ return {
1256
+ success: response.success,
1257
+ eligibility: {
1258
+ participantId: response.eligibility?.participant_id ?? participantId,
1259
+ eligible: Boolean(response.eligibility?.eligible),
1260
+ availableBalance: response.eligibility?.available_balance ?? 0,
1261
+ issues: response.eligibility?.issues || [],
1262
+ requirements: response.eligibility?.requirements || {}
1263
+ }
1264
+ };
1265
+ }
1266
+ // === LEDGER MANAGEMENT ===
1267
+ async createLedger(req) {
1268
+ const response = await this.request("create-ledger", {
1269
+ business_name: req.businessName,
1270
+ owner_email: req.ownerEmail,
1271
+ ledger_mode: req.ledgerMode,
1272
+ settings: req.settings ? {
1273
+ default_tax_rate: req.settings.defaultTaxRate,
1274
+ default_split_percent: req.settings.defaultSplitPercent,
1275
+ platform_fee_percent: req.settings.platformFeePercent,
1276
+ min_payout_amount: req.settings.minPayoutAmount,
1277
+ payout_schedule: req.settings.payoutSchedule,
1278
+ tax_withholding_percent: req.settings.taxWithholdingPercent,
1279
+ currency: req.settings.currency,
1280
+ fiscal_year_start: req.settings.fiscalYearStart,
1281
+ receipt_threshold: req.settings.receiptThreshold
1282
+ } : void 0
1283
+ });
1284
+ return {
1285
+ success: response.success,
1286
+ ledger: {
1287
+ id: response.ledger.id,
1288
+ businessName: response.ledger.business_name,
1289
+ ledgerMode: response.ledger.ledger_mode,
1290
+ apiKey: response.ledger.api_key,
1291
+ status: response.ledger.status,
1292
+ createdAt: response.ledger.created_at
1293
+ },
1294
+ warning: response.warning
1295
+ };
1296
+ }
1297
+ // === ACCOUNTING ADJUSTMENTS ===
1298
+ async recordAdjustment(req) {
1299
+ return this.request("record-adjustment", {
1300
+ adjustment_type: req.adjustmentType,
1301
+ adjustment_date: req.adjustmentDate,
1302
+ entries: req.entries.map((e) => ({
1303
+ account_type: e.accountType,
1304
+ entity_id: e.entityId,
1305
+ entry_type: e.entryType,
1306
+ amount: e.amount
1307
+ })),
1308
+ reason: req.reason,
1309
+ original_transaction_id: req.originalTransactionId,
1310
+ supporting_documentation: req.supportingDocumentation,
1311
+ prepared_by: req.preparedBy
1312
+ });
1313
+ }
1314
+ async recordOpeningBalance(req) {
1315
+ return this.request("record-opening-balance", {
1316
+ as_of_date: req.asOfDate,
1317
+ source: req.source,
1318
+ source_description: req.sourceDescription,
1319
+ balances: req.balances.map((b) => ({
1320
+ account_type: b.accountType,
1321
+ entity_id: b.entityId,
1322
+ balance: b.balance
1323
+ }))
1324
+ });
1325
+ }
1326
+ async recordTransfer(req) {
1327
+ return this.request("record-transfer", {
1328
+ from_account_type: req.fromAccountType,
1329
+ to_account_type: req.toAccountType,
1330
+ amount: req.amount,
1331
+ transfer_type: req.transferType,
1332
+ description: req.description,
1333
+ reference_id: req.referenceId
1334
+ });
1335
+ }
1336
+ // === RISK & POLICY ===
1337
+ async evaluateFraud(req) {
1338
+ const response = await this.request("fraud/evaluations", {
1339
+ idempotency_key: req.idempotencyKey,
1340
+ amount: req.amount,
1341
+ currency: req.currency,
1342
+ counterparty_name: req.counterpartyName,
1343
+ authorizing_instrument_id: req.authorizingInstrumentId,
1344
+ expected_date: req.expectedDate,
1345
+ category: req.category
1346
+ });
1347
+ return {
1348
+ success: response.success,
1349
+ cached: response.cached,
1350
+ evaluation: {
1351
+ id: response.evaluation.id,
1352
+ signal: response.evaluation.signal,
1353
+ riskFactors: (response.evaluation.risk_factors || []).map((f) => ({
1354
+ policyId: f.policy_id,
1355
+ policyType: f.policy_type,
1356
+ severity: f.severity,
1357
+ indicator: f.indicator
1358
+ })),
1359
+ validUntil: response.evaluation.valid_until,
1360
+ createdAt: response.evaluation.created_at,
1361
+ acknowledgedAt: response.evaluation.acknowledged_at
1362
+ }
1363
+ };
1364
+ }
1365
+ async createFraudPolicy(req) {
1366
+ const response = await this.request("fraud/policies", {
1367
+ policy_type: req.policyType,
1368
+ config: req.config,
1369
+ severity: req.severity,
1370
+ priority: req.priority
1371
+ });
1372
+ return {
1373
+ success: response.success,
1374
+ policy: {
1375
+ id: response.policy.id,
1376
+ type: response.policy.type,
1377
+ severity: response.policy.severity,
1378
+ priority: response.policy.priority,
1379
+ isActive: Boolean(response.policy.is_active),
1380
+ config: response.policy.config || {},
1381
+ createdAt: response.policy.created_at ?? null,
1382
+ updatedAt: response.policy.updated_at ?? null
1383
+ }
1384
+ };
1385
+ }
1386
+ async listFraudPolicies() {
1387
+ const response = await this.requestGet("fraud/policies");
1388
+ return {
1389
+ success: response.success,
1390
+ policies: (response.policies || []).map((policy) => ({
1391
+ id: policy.id,
1392
+ type: policy.type,
1393
+ severity: policy.severity,
1394
+ priority: policy.priority,
1395
+ isActive: Boolean(policy.is_active),
1396
+ config: policy.config || {},
1397
+ createdAt: policy.created_at ?? null,
1398
+ updatedAt: policy.updated_at ?? null
1399
+ }))
1400
+ };
1401
+ }
1402
+ async deleteFraudPolicy(policyId) {
1403
+ const response = await this.requestDelete(`fraud/policies/${policyId}`);
1404
+ return {
1405
+ success: response.success,
1406
+ deleted: Boolean(response.deleted),
1407
+ policyId: response.policy_id
1408
+ };
1409
+ }
1410
+ // === TAX DOCUMENTS ===
1411
+ async calculateTaxForParticipant(participantId, taxYear) {
1412
+ const response = await this.requestGet(`tax/calculations/${participantId}`, {
1413
+ tax_year: taxYear
1414
+ });
1415
+ return {
1416
+ success: response.success,
1417
+ calculation: {
1418
+ participantId: response.calculation.participant_id,
1419
+ taxYear: response.calculation.tax_year,
1420
+ grossPayments: response.calculation.gross_payments,
1421
+ transactionCount: response.calculation.transaction_count,
1422
+ requires1099: Boolean(response.calculation.requires_1099),
1423
+ monthlyTotals: response.calculation.monthly_totals || {},
1424
+ threshold: response.calculation.threshold,
1425
+ linkedUserId: response.calculation.linked_user_id ?? null,
1426
+ sharedTaxProfile: response.calculation.shared_tax_profile ? {
1427
+ status: response.calculation.shared_tax_profile.status,
1428
+ legalName: response.calculation.shared_tax_profile.legal_name ?? null,
1429
+ taxIdLast4: response.calculation.shared_tax_profile.tax_id_last4 ?? null
1430
+ } : null
1431
+ }
1432
+ };
1433
+ }
1434
+ async generateAllTaxDocuments(taxYear) {
1435
+ const response = await this.request("tax/documents/generate", { tax_year: taxYear });
1436
+ return {
1437
+ success: response.success,
1438
+ generation: {
1439
+ taxYear: response.generation.tax_year,
1440
+ created: response.generation.created,
1441
+ skipped: response.generation.skipped,
1442
+ totalAmount: response.generation.total_amount
1443
+ }
1444
+ };
1445
+ }
1446
+ async listTaxDocuments(taxYear) {
1447
+ const response = await this.requestGet("tax/documents", { tax_year: taxYear });
1448
+ return {
1449
+ success: response.success,
1450
+ taxYear: response.tax_year,
1451
+ summary: {
1452
+ totalDocuments: response.summary?.total_documents ?? 0,
1453
+ totalAmount: response.summary?.total_amount ?? 0,
1454
+ byStatus: {
1455
+ calculated: response.summary?.by_status?.calculated ?? 0,
1456
+ exported: response.summary?.by_status?.exported ?? 0,
1457
+ filed: response.summary?.by_status?.filed ?? 0
1458
+ }
1459
+ },
1460
+ documents: response.documents || []
1461
+ };
1462
+ }
1463
+ async getTaxDocument(documentId) {
1464
+ const response = await this.requestGet(`tax/documents/${documentId}`);
1465
+ return {
1466
+ success: response.success,
1467
+ document: response.document
1468
+ };
1469
+ }
1470
+ async exportTaxDocuments(taxYear, format = "json") {
1471
+ if (format === "csv") {
1472
+ const response = await this.requestGetRaw("tax/documents/export", { tax_year: taxYear, format });
1473
+ const csv = await response.text();
1474
+ const disposition = response.headers.get("Content-Disposition") || "";
1475
+ const filenameMatch = disposition.match(/filename="?([^"]+)"?/);
1476
+ return { csv, filename: filenameMatch?.[1] || `1099_export_${taxYear}.csv` };
1477
+ }
1478
+ return this.requestGet("tax/documents/export", { tax_year: taxYear, format });
1479
+ }
1480
+ async markTaxDocumentFiled(documentId) {
1481
+ const response = await this.request(`tax/documents/${documentId}/mark-filed`, {});
1482
+ return {
1483
+ success: response.success,
1484
+ document: {
1485
+ id: response.document.id,
1486
+ tax_year: response.document.tax_year,
1487
+ status: response.document.status
1488
+ }
1489
+ };
1490
+ }
1491
+ async generateTaxSummary(taxYear, creatorId) {
1492
+ const response = await this.requestGet(`tax/summaries/${taxYear}`, {
1493
+ participant_id: creatorId
1494
+ });
1495
+ return {
1496
+ success: response.success,
1497
+ taxYear: response.tax_year,
1498
+ note: response.note,
1499
+ summaries: (response.summaries || []).map((summary) => ({
1500
+ participantId: summary.participant_id,
1501
+ linkedUserId: summary.linked_user_id ?? null,
1502
+ grossEarnings: summary.gross_earnings,
1503
+ refundsIssued: summary.refunds_issued,
1504
+ netEarnings: summary.net_earnings,
1505
+ totalPaidOut: summary.total_paid_out,
1506
+ requires1099: Boolean(summary.requires_1099),
1507
+ sharedTaxProfile: summary.shared_tax_profile ? {
1508
+ status: summary.shared_tax_profile.status,
1509
+ legalName: summary.shared_tax_profile.legal_name ?? null,
1510
+ taxIdLast4: summary.shared_tax_profile.tax_id_last4 ?? null
1511
+ } : null
1512
+ })),
1513
+ totals: {
1514
+ totalGross: response.totals.total_gross,
1515
+ totalRefunds: response.totals.total_refunds,
1516
+ totalNet: response.totals.total_net,
1517
+ totalPaid: response.totals.total_paid,
1518
+ participantsRequiring1099: response.totals.participants_requiring_1099
1519
+ }
1520
+ };
1521
+ }
1522
+ async markTaxDocumentsFiledBulk(taxYear) {
1523
+ return this.request("tax/documents/mark-filed", { tax_year: taxYear });
1524
+ }
1525
+ async correctTaxDocument(documentId, params) {
1526
+ return this.request(`tax/documents/${documentId}/correct`, {
1527
+ reason: params.reason,
1528
+ gross_amount: params.grossAmount,
1529
+ federal_withholding: params.federalWithholding,
1530
+ state_withholding: params.stateWithholding
1531
+ });
1532
+ }
1533
+ async deliverTaxDocumentCopyB(taxYear) {
1534
+ return this.request("tax/documents/deliver-copy-b", { tax_year: taxYear });
1535
+ }
1536
+ async generateTaxDocumentPdf(documentId, copyType) {
1537
+ return this.request(`tax/documents/${documentId}/pdf`, {
1538
+ copy_type: copyType
1539
+ });
1540
+ }
1541
+ async generateTaxDocumentPdfBatch(taxYear, copyType) {
1542
+ return this.request("tax/documents/pdf/batch", {
1543
+ tax_year: taxYear,
1544
+ copy_type: copyType
1545
+ });
1546
+ }
1547
+ // === COMPLIANCE MONITORING ===
1548
+ async getComplianceOverview(options) {
1549
+ const response = await this.requestGet("compliance/overview", {
1550
+ days: options?.days,
1551
+ hours: options?.hours
1552
+ });
1553
+ return {
1554
+ success: response.success,
1555
+ overview: {
1556
+ windowDays: response.overview.window_days,
1557
+ accessWindowHours: response.overview.access_window_hours,
1558
+ totalEvents: response.overview.total_events,
1559
+ uniqueIps: response.overview.unique_ips,
1560
+ uniqueActors: response.overview.unique_actors,
1561
+ highRiskEvents: response.overview.high_risk_events,
1562
+ criticalRiskEvents: response.overview.critical_risk_events,
1563
+ failedAuthEvents: response.overview.failed_auth_events,
1564
+ payoutsFailed: response.overview.payouts_failed,
1565
+ refundsRecorded: response.overview.refunds_recorded,
1566
+ disputeEvents: response.overview.dispute_events
1567
+ },
1568
+ note: response.note
1569
+ };
1570
+ }
1571
+ async listComplianceAccessPatterns(options) {
1572
+ const response = await this.requestGet("compliance/access-patterns", {
1573
+ hours: options?.hours,
1574
+ limit: options?.limit
1575
+ });
1576
+ return {
1577
+ success: response.success,
1578
+ windowHours: response.window_hours,
1579
+ count: response.count,
1580
+ patterns: (response.patterns || []).map((pattern) => ({
1581
+ ipAddress: pattern.ip_address,
1582
+ hour: pattern.hour,
1583
+ requestCount: pattern.request_count,
1584
+ uniqueActions: pattern.unique_actions,
1585
+ actions: pattern.actions || [],
1586
+ maxRiskScore: pattern.max_risk_score,
1587
+ failedAuths: pattern.failed_auths
1588
+ }))
1589
+ };
1590
+ }
1591
+ async listComplianceFinancialActivity(options) {
1592
+ const response = await this.requestGet("compliance/financial-activity", {
1593
+ days: options?.days
1594
+ });
1595
+ return {
1596
+ success: response.success,
1597
+ windowDays: response.window_days,
1598
+ activity: (response.activity || []).map((entry) => ({
1599
+ date: entry.date,
1600
+ payoutsInitiated: entry.payouts_initiated,
1601
+ payoutsCompleted: entry.payouts_completed,
1602
+ payoutsFailed: entry.payouts_failed,
1603
+ salesRecorded: entry.sales_recorded,
1604
+ refundsRecorded: entry.refunds_recorded,
1605
+ disputeEvents: entry.dispute_events
1606
+ }))
1607
+ };
1608
+ }
1609
+ async listComplianceSecuritySummary(options) {
1610
+ const response = await this.requestGet("compliance/security-summary", {
1611
+ days: options?.days
1612
+ });
1613
+ return {
1614
+ success: response.success,
1615
+ windowDays: response.window_days,
1616
+ summary: (response.summary || []).map((entry) => ({
1617
+ date: entry.date,
1618
+ action: entry.action,
1619
+ eventCount: entry.event_count,
1620
+ uniqueIps: entry.unique_ips,
1621
+ uniqueActors: entry.unique_actors,
1622
+ avgRiskScore: entry.avg_risk_score,
1623
+ maxRiskScore: entry.max_risk_score,
1624
+ highRiskCount: entry.high_risk_count,
1625
+ criticalRiskCount: entry.critical_risk_count
1626
+ }))
1627
+ };
1628
+ }
1629
+ async exportReport(req) {
1630
+ const body = {
1631
+ report_type: req.reportType,
1632
+ format: req.format,
1633
+ start_date: req.startDate,
1634
+ end_date: req.endDate,
1635
+ creator_id: req.creatorId
1636
+ };
1637
+ if (req.format === "csv") {
1638
+ const response = await this.requestRaw("export-report", body);
1639
+ const csv = await response.text();
1640
+ const disposition = response.headers.get("Content-Disposition") || "";
1641
+ const filenameMatch = disposition.match(/filename="?([^"]+)"?/);
1642
+ return { csv, filename: filenameMatch?.[1] || `${req.reportType}.csv` };
1643
+ }
1644
+ return this.request("export-report", body);
1645
+ }
1646
+ // === RECEIPTS ===
1647
+ async uploadReceipt(req) {
1648
+ return this.request("upload-receipt", {
1649
+ file_url: req.fileUrl,
1650
+ file_name: req.fileName,
1651
+ file_size: req.fileSize,
1652
+ mime_type: req.mimeType,
1653
+ merchant_name: req.merchantName,
1654
+ transaction_date: req.transactionDate,
1655
+ total_amount: req.totalAmount,
1656
+ transaction_id: req.transactionId
1657
+ });
1658
+ }
1659
+ // === PAYMENTS ===
1660
+ async receivePayment(req) {
1661
+ return this.request("receive-payment", {
1662
+ amount: req.amount,
1663
+ invoice_transaction_id: req.invoiceTransactionId,
1664
+ customer_name: req.customerName,
1665
+ customer_id: req.customerId,
1666
+ reference_id: req.referenceId,
1667
+ payment_method: req.paymentMethod,
1668
+ payment_date: req.paymentDate,
1669
+ metadata: req.metadata
1670
+ });
1671
+ }
1672
+ // === BREACH ALERTS ===
1673
+ async sendBreachAlert(req) {
1674
+ const response = await this.request("send-breach-alert", {
1675
+ cash_balance: req.cashBalance,
1676
+ pending_total: req.pendingTotal,
1677
+ shortfall: req.shortfall,
1678
+ coverage_ratio: req.coverageRatio,
1679
+ triggered_by: req.triggeredBy,
1680
+ instrument_id: req.instrumentId,
1681
+ external_ref: req.externalRef,
1682
+ projections_created: req.projectionsCreated,
1683
+ channel: req.channel
1684
+ });
1685
+ return {
1686
+ success: response.success,
1687
+ message: response.message,
1688
+ alertsSent: response.alerts_sent ?? 0,
1689
+ alertsFailed: response.alerts_failed,
1690
+ alertsSkipped: response.alerts_skipped,
1691
+ results: response.results ? response.results.map((r) => ({
1692
+ channel: r.channel,
1693
+ success: r.success,
1694
+ error: r.error
1695
+ })) : void 0
1696
+ };
1697
+ }
1698
+ // === WALLETS ===
1699
+ mapWalletObject(wallet) {
1700
+ return {
1701
+ id: wallet.id,
1702
+ object: "wallet",
1703
+ walletType: wallet.wallet_type,
1704
+ scopeType: wallet.scope_type,
1705
+ ownerId: wallet.owner_id ?? null,
1706
+ ownerType: wallet.owner_type ?? null,
1707
+ participantId: wallet.participant_id ?? null,
1708
+ accountType: wallet.account_type,
1709
+ name: wallet.name ?? null,
1710
+ currency: wallet.currency,
1711
+ status: wallet.status,
1712
+ balance: wallet.balance,
1713
+ heldAmount: wallet.held_amount ?? 0,
1714
+ availableBalance: wallet.available_balance ?? wallet.balance,
1715
+ redeemable: wallet.redeemable === true,
1716
+ transferable: wallet.transferable === true,
1717
+ topupSupported: wallet.topup_supported === true,
1718
+ payoutSupported: wallet.payout_supported === true,
1719
+ createdAt: wallet.created_at ?? null,
1720
+ metadata: wallet.metadata || {}
1721
+ };
1722
+ }
1723
+ async listWallets(filters = {}) {
1724
+ const response = await this.requestGet("wallets", {
1725
+ owner_id: filters.ownerId,
1726
+ owner_type: filters.ownerType,
1727
+ wallet_type: filters.walletType,
1728
+ limit: filters.limit,
1729
+ offset: filters.offset
1730
+ });
1731
+ return {
1732
+ success: response.success,
1733
+ wallets: (response.wallets || []).map((wallet) => this.mapWalletObject(wallet)),
1734
+ total: response.total,
1735
+ limit: response.limit,
1736
+ offset: response.offset
1737
+ };
1738
+ }
1739
+ async createWallet(req) {
1740
+ const response = await this.request("wallets", {
1741
+ owner_id: req.ownerId,
1742
+ participant_id: req.participantId,
1743
+ owner_type: req.ownerType,
1744
+ wallet_type: req.walletType,
1745
+ name: req.name,
1746
+ metadata: req.metadata
1747
+ });
1748
+ return {
1749
+ success: response.success,
1750
+ created: response.created === true,
1751
+ wallet: this.mapWalletObject(response.wallet)
1752
+ };
1753
+ }
1754
+ async getWallet(walletId) {
1755
+ const response = await this.requestGet(`wallets/${walletId}`);
1756
+ return {
1757
+ success: response.success,
1758
+ wallet: this.mapWalletObject(response.wallet)
1759
+ };
1760
+ }
1761
+ async getWalletEntries(walletId, options) {
1762
+ const response = await this.requestGet(`wallets/${walletId}/entries`, {
1763
+ limit: options?.limit,
1764
+ offset: options?.offset
1765
+ });
1766
+ return {
1767
+ success: response.success,
1768
+ wallet: response.wallet ? this.mapWalletObject(response.wallet) : null,
1769
+ entries: (response.entries || []).map((t) => ({
1770
+ entryId: t.entry_id,
1771
+ entryType: t.entry_type,
1772
+ amount: t.amount,
1773
+ transactionId: t.transaction_id,
1774
+ referenceId: t.reference_id,
1775
+ transactionType: t.transaction_type,
1776
+ description: t.description,
1777
+ status: t.status,
1778
+ metadata: t.metadata,
1779
+ createdAt: t.created_at
1780
+ })),
1781
+ total: response.total,
1782
+ limit: response.limit,
1783
+ offset: response.offset
1784
+ };
1785
+ }
1786
+ async topUpWallet(req) {
1787
+ const response = await this.request(`wallets/${req.walletId}/topups`, {
1788
+ amount: req.amount,
1789
+ reference_id: req.referenceId,
1790
+ description: req.description,
1791
+ metadata: req.metadata
1792
+ });
1793
+ const topup = response.topup || response.deposit || response;
1794
+ return {
1795
+ success: response.success,
1796
+ walletId: topup.wallet_id ?? null,
1797
+ ownerId: topup.owner_id ?? null,
1798
+ transactionId: topup.transaction_id ?? null,
1799
+ balance: topup.balance ?? null
1800
+ };
1801
+ }
1802
+ async withdrawFromWallet(req) {
1803
+ const response = await this.request(`wallets/${req.walletId}/withdrawals`, {
1804
+ amount: req.amount,
1805
+ reference_id: req.referenceId,
1806
+ description: req.description,
1807
+ metadata: req.metadata
1808
+ });
1809
+ const withdrawal = response.withdrawal || response;
1810
+ return {
1811
+ success: response.success,
1812
+ walletId: withdrawal.wallet_id ?? null,
1813
+ ownerId: withdrawal.owner_id ?? null,
1814
+ transactionId: withdrawal.transaction_id ?? null,
1815
+ balance: withdrawal.balance ?? null
1816
+ };
1817
+ }
1818
+ async createTransfer(req) {
1819
+ const response = await this.request("transfers", {
1820
+ from_participant_id: req.fromParticipantId,
1821
+ to_participant_id: req.toParticipantId,
1822
+ amount: req.amount,
1823
+ reference_id: req.referenceId,
1824
+ description: req.description,
1825
+ metadata: req.metadata
1826
+ });
1827
+ const transfer = response.transfer || response;
1828
+ return {
1829
+ success: response.success,
1830
+ transfer: {
1831
+ transactionId: transfer.transaction_id,
1832
+ fromParticipantId: req.fromParticipantId,
1833
+ toParticipantId: req.toParticipantId,
1834
+ fromBalance: transfer.from_balance,
1835
+ toBalance: transfer.to_balance
1836
+ }
1837
+ };
1838
+ }
1839
+ async listHolds(options) {
1840
+ const response = await this.requestGet("holds", {
1841
+ participant_id: options?.participantId,
1842
+ venture_id: options?.ventureId,
1843
+ ready_only: options?.readyOnly,
1844
+ limit: options?.limit
1845
+ });
1846
+ return {
1847
+ success: response.success,
1848
+ holds: (response.holds || []).map((hold) => ({
1849
+ id: hold.id,
1850
+ participantId: hold.participant_id ?? null,
1851
+ participantName: hold.participant_name ?? null,
1852
+ amount: hold.amount,
1853
+ currency: hold.currency,
1854
+ heldSince: hold.held_since,
1855
+ daysHeld: hold.days_held,
1856
+ holdReason: hold.hold_reason ?? null,
1857
+ holdUntil: hold.hold_until ?? null,
1858
+ readyForRelease: Boolean(hold.ready_for_release),
1859
+ releaseStatus: hold.release_status,
1860
+ transactionReference: hold.transaction_reference ?? null,
1861
+ productName: hold.product_name ?? null,
1862
+ ventureId: hold.venture_id ?? null,
1863
+ connectedAccountReady: Boolean(hold.connected_account_ready)
1864
+ })),
1865
+ count: response.count ?? 0
1866
+ };
1867
+ }
1868
+ async getHoldSummary() {
1869
+ const response = await this.requestGet("holds/summary");
1870
+ return {
1871
+ success: response.success,
1872
+ summary: response.summary || {}
1873
+ };
1874
+ }
1875
+ async releaseHold(req) {
1876
+ const response = await this.request(`holds/${req.holdId}/release`, {
1877
+ execute_transfer: req.executeTransfer !== false
1878
+ });
1879
+ const release = response.release || response;
1880
+ return {
1881
+ success: response.success,
1882
+ release: {
1883
+ id: release.id,
1884
+ holdId: release.hold_id ?? req.holdId,
1885
+ executed: Boolean(release.executed),
1886
+ transferId: release.transfer_id ?? null,
1887
+ transferStatus: release.transfer_status ?? null,
1888
+ amount: release.amount ?? null,
1889
+ currency: release.currency ?? null
1890
+ }
1891
+ };
1892
+ }
1893
+ async createCheckoutSession(req) {
1894
+ const hasPaymentMethod = "paymentMethodId" in req ? Boolean(req.paymentMethodId || req.sourceId) : false;
1895
+ if (!hasPaymentMethod && !req.successUrl) {
1896
+ throw new Error("Either paymentMethodId/sourceId or successUrl is required");
1897
+ }
1898
+ const response = await this.request("checkout-sessions", {
1899
+ amount: req.amount,
1900
+ participant_id: req.participantId,
1901
+ currency: req.currency,
1902
+ product_id: req.productId,
1903
+ product_name: req.productName,
1904
+ customer_email: req.customerEmail,
1905
+ customer_id: req.customerId,
1906
+ payment_method_id: "paymentMethodId" in req ? req.paymentMethodId : void 0,
1907
+ source_id: "sourceId" in req ? req.sourceId : void 0,
1908
+ success_url: req.successUrl,
1909
+ cancel_url: req.cancelUrl,
1910
+ idempotency_key: "idempotencyKey" in req ? req.idempotencyKey : void 0,
1911
+ metadata: req.metadata
1912
+ });
1913
+ const checkoutSession = response.checkout_session || response;
1914
+ return {
1915
+ success: Boolean(response.success),
1916
+ checkoutSession: {
1917
+ id: checkoutSession.id ?? checkoutSession.payment_id ?? checkoutSession.payment_intent_id,
1918
+ mode: checkoutSession.mode === "session" ? "session" : "direct",
1919
+ checkoutUrl: checkoutSession.checkout_url ?? null,
1920
+ paymentId: checkoutSession.payment_id ?? null,
1921
+ paymentIntentId: checkoutSession.payment_intent_id ?? checkoutSession.payment_id ?? null,
1922
+ status: checkoutSession.status ?? null,
1923
+ requiresAction: Boolean(checkoutSession.requires_action),
1924
+ amount: checkoutSession.amount ?? req.amount,
1925
+ currency: checkoutSession.currency ?? (req.currency || "USD"),
1926
+ expiresAt: checkoutSession.expires_at ?? null,
1927
+ fundingTransactionId: checkoutSession.funding_transaction_id ?? null,
1928
+ saleTransactionId: checkoutSession.sale_transaction_id ?? null,
1929
+ saleReference: checkoutSession.sale_reference ?? null,
1930
+ breakdown: checkoutSession.breakdown ? {
1931
+ grossAmount: checkoutSession.breakdown.gross_amount,
1932
+ creatorAmount: checkoutSession.breakdown.creator_amount,
1933
+ platformAmount: checkoutSession.breakdown.platform_amount,
1934
+ creatorPercent: checkoutSession.breakdown.creator_percent
1935
+ } : null
1936
+ }
1937
+ };
1938
+ }
1939
+ async createPayout(req) {
1940
+ const response = await this.request("payouts", {
1941
+ participant_id: req.participantId,
1942
+ wallet_id: req.walletId,
1943
+ amount: req.amount,
1944
+ reference_id: req.referenceId,
1945
+ reference_type: req.referenceType,
1946
+ description: req.description,
1947
+ payout_method: req.payoutMethod,
1948
+ fees: req.fees,
1949
+ fees_paid_by: req.feesPaidBy,
1950
+ metadata: req.metadata
1951
+ });
1952
+ const payout = response.payout || response;
1953
+ return {
1954
+ success: response.success,
1955
+ payout: {
1956
+ id: payout.id,
1957
+ transactionId: payout.transaction_id,
1958
+ grossAmount: payout.gross_amount ?? null,
1959
+ fees: payout.fees ?? null,
1960
+ netAmount: payout.net_amount ?? null,
1961
+ previousBalance: payout.previous_balance ?? null,
1962
+ newBalance: payout.new_balance ?? null
1963
+ }
1964
+ };
1965
+ }
1966
+ async createRefund(req) {
1967
+ const response = await this.request("refunds", {
1968
+ sale_reference: req.saleReference,
1969
+ reason: req.reason,
1970
+ amount: req.amount,
1971
+ refund_from: req.refundFrom,
1972
+ external_refund_id: req.externalRefundId,
1973
+ idempotency_key: req.idempotencyKey,
1974
+ metadata: req.metadata
1975
+ });
1976
+ const refund = response.refund || response;
1977
+ return {
1978
+ success: response.success,
1979
+ warning: response.warning ?? null,
1980
+ warningCode: response.warning_code ?? null,
1981
+ refund: {
1982
+ id: refund.id ?? refund.reference_id ?? refund.transaction_id ?? "",
1983
+ transactionId: refund.transaction_id ?? null,
1984
+ referenceId: refund.reference_id ?? null,
1985
+ saleReference: refund.sale_reference ?? null,
1986
+ refundedAmount: refund.refunded_amount ?? null,
1987
+ currency: refund.currency ?? null,
1988
+ status: refund.status ?? null,
1989
+ breakdown: refund.breakdown ? {
1990
+ fromCreator: refund.breakdown.from_creator,
1991
+ fromPlatform: refund.breakdown.from_platform
1992
+ } : null,
1993
+ isFullRefund: refund.is_full_refund ?? null,
1994
+ repairPending: refund.repair_pending ?? null
1995
+ }
1996
+ };
1997
+ }
1998
+ async listRefunds(req = {}) {
1999
+ const response = await this.requestGet("refunds", {
2000
+ sale_reference: req.saleReference,
2001
+ limit: req.limit
2002
+ });
2003
+ return {
2004
+ success: response.success,
2005
+ count: response.count ?? (response.refunds || []).length,
2006
+ refunds: (response.refunds || []).map((refund) => ({
2007
+ id: refund.id,
2008
+ transactionId: refund.transaction_id ?? null,
2009
+ referenceId: refund.reference_id ?? null,
2010
+ saleReference: refund.sale_reference ?? null,
2011
+ refundedAmount: refund.refunded_amount,
2012
+ currency: refund.currency,
2013
+ status: refund.status,
2014
+ reason: refund.reason ?? null,
2015
+ refundFrom: refund.refund_from ?? null,
2016
+ externalRefundId: refund.external_refund_id ?? null,
2017
+ createdAt: refund.created_at ?? null,
2018
+ breakdown: refund.breakdown ? {
2019
+ fromCreator: refund.breakdown.from_creator,
2020
+ fromPlatform: refund.breakdown.from_platform
2021
+ } : null,
2022
+ repairPending: refund.repair_pending ?? null,
2023
+ lastError: refund.last_error ?? null
2024
+ }))
2025
+ };
2026
+ }
2027
+ // === INVOICES ===
2028
+ async createInvoice(req) {
2029
+ return this.request("invoices", {
2030
+ customer_name: req.customerName,
2031
+ customer_email: req.customerEmail,
2032
+ customer_id: req.customerId,
2033
+ customer_address: req.customerAddress ? {
2034
+ line1: req.customerAddress.line1,
2035
+ line2: req.customerAddress.line2,
2036
+ city: req.customerAddress.city,
2037
+ state: req.customerAddress.state,
2038
+ postal_code: req.customerAddress.postalCode,
2039
+ country: req.customerAddress.country
2040
+ } : void 0,
2041
+ line_items: req.lineItems.map((item) => ({
2042
+ description: item.description,
2043
+ quantity: item.quantity,
2044
+ unit_price: item.unitPrice,
2045
+ amount: item.amount ?? Math.round(item.quantity * item.unitPrice)
2046
+ })),
2047
+ due_date: req.dueDate,
2048
+ notes: req.notes,
2049
+ terms: req.terms,
2050
+ reference_id: req.referenceId,
2051
+ metadata: req.metadata
2052
+ });
2053
+ }
2054
+ async listInvoices(options) {
2055
+ return this.requestGet("invoices", {
2056
+ status: options?.status,
2057
+ customer_id: options?.customerId,
2058
+ limit: options?.limit,
2059
+ offset: options?.offset
2060
+ });
2061
+ }
2062
+ async getInvoice(invoiceId) {
2063
+ return this.requestGet(`invoices/${invoiceId}`);
2064
+ }
2065
+ async sendInvoice(invoiceId) {
2066
+ return this.request(`invoices/${invoiceId}/send`, {});
2067
+ }
2068
+ async recordInvoicePayment(invoiceId, req) {
2069
+ return this.request(`invoices/${invoiceId}/record-payment`, {
2070
+ amount: req.amount,
2071
+ payment_method: req.paymentMethod,
2072
+ payment_date: req.paymentDate,
2073
+ reference_id: req.referenceId,
2074
+ notes: req.notes
2075
+ });
2076
+ }
2077
+ async voidInvoice(invoiceId, reason) {
2078
+ return this.request(`invoices/${invoiceId}/void`, { reason });
2079
+ }
2080
+ // === PAY BILL ===
2081
+ async payBill(req) {
2082
+ return this.request("pay-bill", {
2083
+ bill_transaction_id: req.billTransactionId,
2084
+ amount: req.amount,
2085
+ vendor_name: req.vendorName,
2086
+ reference_id: req.referenceId,
2087
+ payment_method: req.paymentMethod,
2088
+ payment_date: req.paymentDate,
2089
+ metadata: req.metadata
2090
+ });
2091
+ }
2092
+ // === BUDGETS ===
2093
+ async createBudget(req) {
2094
+ return this.request("manage-budgets", {
2095
+ name: req.name,
2096
+ category_code: req.categoryCode,
2097
+ budget_amount: req.budgetAmount,
2098
+ budget_period: req.budgetPeriod,
2099
+ alert_at_percentage: req.alertAtPercentage
2100
+ });
2101
+ }
2102
+ async listBudgets() {
2103
+ return this.requestGet("manage-budgets");
2104
+ }
2105
+ // === RECURRING EXPENSES ===
2106
+ async createRecurring(req) {
2107
+ return this.request("manage-recurring", {
2108
+ name: req.name,
2109
+ merchant_name: req.merchantName,
2110
+ category_code: req.categoryCode,
2111
+ amount: req.amount,
2112
+ recurrence_interval: req.recurrenceInterval,
2113
+ recurrence_day: req.recurrenceDay,
2114
+ start_date: req.startDate,
2115
+ end_date: req.endDate,
2116
+ business_purpose: req.businessPurpose,
2117
+ is_variable_amount: req.isVariableAmount
2118
+ });
2119
+ }
2120
+ async listRecurring() {
2121
+ return this.requestGet("manage-recurring");
2122
+ }
2123
+ async getDueRecurring(days) {
2124
+ return this.requestGet("manage-recurring/due", { days });
2125
+ }
2126
+ // === CONTRACTORS ===
2127
+ async createContractor(req) {
2128
+ return this.request("manage-contractors", {
2129
+ name: req.name,
2130
+ email: req.email,
2131
+ company_name: req.companyName
2132
+ });
2133
+ }
2134
+ async listContractors() {
2135
+ return this.requestGet("manage-contractors");
2136
+ }
2137
+ async recordContractorPayment(req) {
2138
+ return this.request("manage-contractors/payment", {
2139
+ contractor_id: req.contractorId,
2140
+ amount: req.amount,
2141
+ payment_date: req.paymentDate,
2142
+ payment_method: req.paymentMethod,
2143
+ payment_reference: req.paymentReference,
2144
+ description: req.description
2145
+ });
2146
+ }
2147
+ // === BANK ACCOUNTS ===
2148
+ async createBankAccount(req) {
2149
+ return this.request("manage-bank-accounts", {
2150
+ bank_name: req.bankName,
2151
+ account_name: req.accountName,
2152
+ account_type: req.accountType,
2153
+ account_last_four: req.accountLastFour
2154
+ });
2155
+ }
2156
+ async listBankAccounts() {
2157
+ return this.requestGet("manage-bank-accounts");
2158
+ }
2159
+ // === LEDGER LISTING ===
2160
+ async listLedgers() {
2161
+ return this.requestGet("list-ledgers");
2162
+ }
2163
+ // === DELETE CREATOR ===
2164
+ async deleteCreator(creatorId) {
2165
+ return this.request("delete-creator", {
2166
+ creator_id: creatorId
2167
+ });
2168
+ }
2169
+ // === TAX INFO ===
2170
+ async submitTaxInfo(req) {
2171
+ return this.request("submit-tax-info", {
2172
+ participant_id: req.participantId,
2173
+ legal_name: req.legalName,
2174
+ tax_id_type: req.taxIdType,
2175
+ tax_id_last4: req.taxIdLast4,
2176
+ business_type: req.businessType,
2177
+ address: req.address ? {
2178
+ line1: req.address.line1,
2179
+ line2: req.address.line2,
2180
+ city: req.address.city,
2181
+ state: req.address.state,
2182
+ postal_code: req.address.postalCode,
2183
+ country: req.address.country
2184
+ } : void 0,
2185
+ certify: req.certify
2186
+ });
2187
+ }
2188
+ // === BANK STATEMENT IMPORT ===
2189
+ async importBankStatement(req) {
2190
+ return this.request("import-bank-statement", {
2191
+ bank_account_id: req.bankAccountId,
2192
+ lines: req.lines.map((line) => ({
2193
+ transaction_date: line.transactionDate,
2194
+ post_date: line.postDate,
2195
+ description: line.description,
2196
+ amount: line.amount,
2197
+ reference_number: line.referenceNumber,
2198
+ check_number: line.checkNumber,
2199
+ merchant_name: line.merchantName,
2200
+ category_hint: line.categoryHint
2201
+ })),
2202
+ auto_match: req.autoMatch
2203
+ });
2204
+ }
2205
+ };
2206
+ var client_default = Soledgic;
2207
+ // Annotate the CommonJS export names for ESM import in node:
2208
+ 0 && (module.exports = {
2209
+ AuthenticationError,
2210
+ ConflictError,
2211
+ DEFAULT_API_VERSION,
2212
+ DEFAULT_BASE_URL,
2213
+ NotFoundError,
2214
+ Soledgic,
2215
+ SoledgicError,
2216
+ ValidationError,
2217
+ hmacHex,
2218
+ isArrayBufferView,
2219
+ mapWebhookDelivery,
2220
+ mapWebhookEndpoint,
2221
+ parseWebhookEvent,
2222
+ parseWebhookSignatureHeader,
2223
+ resolveWebhookEndpointUrl,
2224
+ timingSafeEqual,
2225
+ verifyWebhookSignature,
2226
+ webhookPayloadToString
2227
+ });