@solvapay/server 1.2.0 → 1.2.1-preview-e89fa52f99b6d0c7bf9834fcf2d1403141051fa0

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.
@@ -29,6 +29,15 @@ interface components {
29
29
  * @example usd
30
30
  */
31
31
  defaultCurrency?: string;
32
+ /**
33
+ * Full set of currencies a customer may pay credit topups in, including the default currency. Omitted/single-entry means single-currency behavior.
34
+ * @example [
35
+ * "USD",
36
+ * "EUR",
37
+ * "GBP"
38
+ * ]
39
+ */
40
+ supportedTopupCurrencies?: string[];
32
41
  /**
33
42
  * Descriptor appearing on the customer card statement
34
43
  * @example ACME INC
@@ -246,6 +255,33 @@ interface components {
246
255
  */
247
256
  checkoutUrl: string;
248
257
  };
258
+ PlanPricingOptionDto: {
259
+ /**
260
+ * ISO 4217 currency code
261
+ * @example USD
262
+ */
263
+ currency: string;
264
+ /**
265
+ * Price in smallest currency unit (e.g. cents)
266
+ * @example 2999
267
+ */
268
+ price: number;
269
+ /**
270
+ * Base price in smallest currency unit (hybrid plans)
271
+ * @example 1999
272
+ */
273
+ basePrice?: number;
274
+ /**
275
+ * One-time setup fee in smallest currency unit
276
+ * @example 500
277
+ */
278
+ setupFee?: number;
279
+ /**
280
+ * Whether this is the default currency option for the plan
281
+ * @example true
282
+ */
283
+ default?: boolean;
284
+ };
249
285
  Plan: {
250
286
  /**
251
287
  * Plan type exposed in SDK
@@ -283,6 +319,8 @@ interface components {
283
319
  * @example USD
284
320
  */
285
321
  currency: string;
322
+ /** @description Per-currency price options for this plan */
323
+ pricingOptions?: components["schemas"]["PlanPricingOptionDto"][];
286
324
  /**
287
325
  * Currency symbol (derived from currency)
288
326
  * @example $
@@ -376,6 +414,13 @@ interface components {
376
414
  price?: number;
377
415
  creditsPerUnit?: number;
378
416
  currency?: string;
417
+ pricingOptions?: {
418
+ currency: string;
419
+ price: number;
420
+ basePrice?: number;
421
+ setupFee?: number;
422
+ default?: boolean;
423
+ }[];
379
424
  /** @enum {string} */
380
425
  billingModel?: "pre-paid" | "post-paid";
381
426
  freeUnits?: number;
@@ -414,6 +459,13 @@ interface components {
414
459
  price?: number;
415
460
  creditsPerUnit?: number;
416
461
  currency?: string;
462
+ pricingOptions?: {
463
+ currency: string;
464
+ price: number;
465
+ basePrice?: number;
466
+ setupFee?: number;
467
+ default?: boolean;
468
+ }[];
417
469
  /** @enum {string} */
418
470
  billingModel?: "pre-paid" | "post-paid";
419
471
  freeUnits?: number;
@@ -658,6 +710,13 @@ interface components {
658
710
  name: string;
659
711
  price: number;
660
712
  currency: string;
713
+ pricingOptions?: {
714
+ currency: string;
715
+ price: number;
716
+ basePrice?: number;
717
+ setupFee?: number;
718
+ default?: boolean;
719
+ }[];
661
720
  /** @enum {string} */
662
721
  billingCycle?: "weekly" | "monthly" | "quarterly" | "yearly" | "custom";
663
722
  /** @enum {string} */
@@ -726,6 +785,13 @@ interface components {
726
785
  name: string;
727
786
  price: number;
728
787
  currency: string;
788
+ pricingOptions?: {
789
+ currency: string;
790
+ price: number;
791
+ basePrice?: number;
792
+ setupFee?: number;
793
+ default?: boolean;
794
+ }[];
729
795
  /** @enum {string} */
730
796
  billingCycle?: "weekly" | "monthly" | "quarterly" | "yearly" | "custom";
731
797
  /** @enum {string} */
@@ -759,6 +825,52 @@ interface components {
759
825
  CloneProductDto: {
760
826
  name?: string;
761
827
  };
828
+ CreditDebitSuccessResponse: {
829
+ /** @enum {number} */
830
+ debited: true;
831
+ /**
832
+ * Credits debited for this usage event
833
+ * @example 10
834
+ */
835
+ amount: number;
836
+ /**
837
+ * Estimated remaining units after debit
838
+ * @example 99
839
+ */
840
+ unitsRemaining: number;
841
+ };
842
+ CreditDebitSkippedResponse: {
843
+ /** @enum {number} */
844
+ debited: false;
845
+ /**
846
+ * Reason no credit debit was recorded
847
+ * @example duplicate
848
+ * @enum {string}
849
+ */
850
+ reason: "duplicate" | "no_product_ref" | "customer_not_found" | "no_active_purchase" | "plan_not_credit_based";
851
+ };
852
+ UsageRecordResponse: {
853
+ /** @example true */
854
+ success: boolean;
855
+ /** @example usage_A1B2C3D4 */
856
+ reference: string;
857
+ creditDebit?: components["schemas"]["CreditDebitSuccessResponse"] | components["schemas"]["CreditDebitSkippedResponse"];
858
+ };
859
+ BulkUsageResultResponse: {
860
+ /** @example usage_A1B2C3D4 */
861
+ reference: string;
862
+ creditDebit?: components["schemas"]["CreditDebitSuccessResponse"] | components["schemas"]["CreditDebitSkippedResponse"];
863
+ };
864
+ BulkUsageResponse: {
865
+ /** @example true */
866
+ success: boolean;
867
+ /**
868
+ * Number of usage events inserted
869
+ * @example 2
870
+ */
871
+ inserted: number;
872
+ results: components["schemas"]["BulkUsageResultResponse"][];
873
+ };
762
874
  CreateUsageRequest: {
763
875
  customerRef: string;
764
876
  /**
@@ -1028,6 +1140,8 @@ interface components {
1028
1140
  creditsPerUnit?: number;
1029
1141
  billingModel?: string;
1030
1142
  billingCycle?: string;
1143
+ /** @description Per-currency price options for this plan */
1144
+ pricingOptions?: components["schemas"]["PlanPricingOptionDto"][];
1031
1145
  };
1032
1146
  LimitBalanceDto: {
1033
1147
  /** @description Credit balance in mils */
@@ -1111,6 +1225,22 @@ interface components {
1111
1225
  };
1112
1226
  externalRef?: string;
1113
1227
  };
1228
+ GrantCustomerCreditsRequest: {
1229
+ credits: number;
1230
+ reason?: string;
1231
+ };
1232
+ GrantCustomerCreditsResponse: {
1233
+ /** @description Whether the grant was recorded */
1234
+ success: boolean;
1235
+ /** @description Customer reference identifier */
1236
+ customerRef: string;
1237
+ /** @description Granted credit amount */
1238
+ credits: number;
1239
+ /** @description Customer credit balance after the grant */
1240
+ balance: number;
1241
+ /** @description Machine-readable grant reason */
1242
+ reason?: string;
1243
+ };
1114
1244
  CreateCustomerSessionRequest: {
1115
1245
  customerRef: string;
1116
1246
  productRef?: string;
@@ -23,6 +23,7 @@ function handleRouteError(error, operationName, defaultMessage) {
23
23
  }
24
24
 
25
25
  // src/helpers/auth.ts
26
+ import { SOLVAPAY_USER_ID_HEADER } from "@solvapay/auth";
26
27
  function base64UrlDecode(input) {
27
28
  const padded = input.replace(/-/g, "+").replace(/_/g, "/");
28
29
  const padding = padded.length % 4 === 0 ? "" : "=".repeat(4 - padded.length % 4);
@@ -99,7 +100,7 @@ async function getAuthenticatedUserCore(request, options = {}) {
99
100
  try {
100
101
  const includeEmail = options.includeEmail !== false;
101
102
  const includeName = options.includeName !== false;
102
- const headerUserId = request.headers.get("x-user-id");
103
+ const headerUserId = request.headers.get(SOLVAPAY_USER_ID_HEADER);
103
104
  if (headerUserId) {
104
105
  let email = null;
105
106
  let name = null;
@@ -178,7 +179,9 @@ function createSolvaPayClient(opts) {
178
179
  if (!res.ok) {
179
180
  const error = await res.text();
180
181
  log(`\u274C API Error: ${res.status} - ${error}`);
181
- throw new SolvaPayError2(`Check limits failed (${res.status}): ${error}`, { status: res.status });
182
+ throw new SolvaPayError2(`Check limits failed (${res.status}): ${error}`, {
183
+ status: res.status
184
+ });
182
185
  }
183
186
  const result = await res.json();
184
187
  return result;
@@ -194,8 +197,28 @@ function createSolvaPayClient(opts) {
194
197
  if (!res.ok) {
195
198
  const error = await res.text();
196
199
  log(`\u274C API Error: ${res.status} - ${error}`);
197
- throw new SolvaPayError2(`Track usage failed (${res.status}): ${error}`, { status: res.status });
200
+ throw new SolvaPayError2(`Track usage failed (${res.status}): ${error}`, {
201
+ status: res.status
202
+ });
198
203
  }
204
+ return await res.json();
205
+ },
206
+ // POST: /v1/sdk/usages/bulk
207
+ async trackUsageBulk(params) {
208
+ const url = `${base}/v1/sdk/usages/bulk`;
209
+ const res = await fetch(url, {
210
+ method: "POST",
211
+ headers,
212
+ body: JSON.stringify(params)
213
+ });
214
+ if (!res.ok) {
215
+ const error = await res.text();
216
+ log(`\u274C API Error: ${res.status} - ${error}`);
217
+ throw new SolvaPayError2(`Track usage bulk failed (${res.status}): ${error}`, {
218
+ status: res.status
219
+ });
220
+ }
221
+ return await res.json();
199
222
  },
200
223
  // POST: /v1/sdk/customers
201
224
  async createCustomer(params) {
@@ -208,7 +231,9 @@ function createSolvaPayClient(opts) {
208
231
  if (!res.ok) {
209
232
  const error = await res.text();
210
233
  log(`\u274C API Error: ${res.status} - ${error}`);
211
- throw new SolvaPayError2(`Create customer failed (${res.status}): ${error}`, { status: res.status });
234
+ throw new SolvaPayError2(`Create customer failed (${res.status}): ${error}`, {
235
+ status: res.status
236
+ });
212
237
  }
213
238
  const result = await res.json();
214
239
  return {
@@ -226,7 +251,9 @@ function createSolvaPayClient(opts) {
226
251
  if (!res.ok) {
227
252
  const error = await res.text();
228
253
  log(`\u274C API Error: ${res.status} - ${error}`);
229
- throw new SolvaPayError2(`Update customer failed (${res.status}): ${error}`, { status: res.status });
254
+ throw new SolvaPayError2(`Update customer failed (${res.status}): ${error}`, {
255
+ status: res.status
256
+ });
230
257
  }
231
258
  const result = await res.json();
232
259
  return {
@@ -256,7 +283,9 @@ function createSolvaPayClient(opts) {
256
283
  if (!res.ok) {
257
284
  const error = await res.text();
258
285
  log(`\u274C API Error: ${res.status} - ${error}`);
259
- throw new SolvaPayError2(`Get customer failed (${res.status}): ${error}`, { status: res.status });
286
+ throw new SolvaPayError2(`Get customer failed (${res.status}): ${error}`, {
287
+ status: res.status
288
+ });
260
289
  }
261
290
  const result = await res.json();
262
291
  let customer = result;
@@ -277,6 +306,27 @@ function createSolvaPayClient(opts) {
277
306
  purchases: customer.purchases || []
278
307
  };
279
308
  },
309
+ // POST: /v1/sdk/customers/{reference}/credits
310
+ async assignCredits(params) {
311
+ const { customerRef, idempotencyKey, ...body } = params;
312
+ const url = `${base}/v1/sdk/customers/${encodeURIComponent(customerRef)}/credits`;
313
+ const res = await fetch(url, {
314
+ method: "POST",
315
+ headers: {
316
+ ...headers,
317
+ ...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
318
+ },
319
+ body: JSON.stringify(body)
320
+ });
321
+ if (!res.ok) {
322
+ const error = await res.text();
323
+ log(`\u274C API Error: ${res.status} - ${error}`);
324
+ throw new SolvaPayError2(`Assign credits failed (${res.status}): ${error}`, {
325
+ status: res.status
326
+ });
327
+ }
328
+ return await res.json();
329
+ },
280
330
  // GET: /v1/sdk/merchant
281
331
  async getMerchant() {
282
332
  const url = `${base}/v1/sdk/merchant`;
@@ -287,7 +337,9 @@ function createSolvaPayClient(opts) {
287
337
  if (!res.ok) {
288
338
  const error = await res.text();
289
339
  log(`\u274C API Error: ${res.status} - ${error}`);
290
- throw new SolvaPayError2(`Get merchant failed (${res.status}): ${error}`, { status: res.status });
340
+ throw new SolvaPayError2(`Get merchant failed (${res.status}): ${error}`, {
341
+ status: res.status
342
+ });
291
343
  }
292
344
  return res.json();
293
345
  },
@@ -301,7 +353,9 @@ function createSolvaPayClient(opts) {
301
353
  if (!res.ok) {
302
354
  const error = await res.text();
303
355
  log(`\u274C API Error: ${res.status} - ${error}`);
304
- throw new SolvaPayError2(`Get platform config failed (${res.status}): ${error}`, { status: res.status });
356
+ throw new SolvaPayError2(`Get platform config failed (${res.status}): ${error}`, {
357
+ status: res.status
358
+ });
305
359
  }
306
360
  return res.json();
307
361
  },
@@ -315,7 +369,9 @@ function createSolvaPayClient(opts) {
315
369
  if (!res.ok) {
316
370
  const error = await res.text();
317
371
  log(`\u274C API Error: ${res.status} - ${error}`);
318
- throw new SolvaPayError2(`Get product failed (${res.status}): ${error}`, { status: res.status });
372
+ throw new SolvaPayError2(`Get product failed (${res.status}): ${error}`, {
373
+ status: res.status
374
+ });
319
375
  }
320
376
  const result = await res.json();
321
377
  const data = result.data || {};
@@ -332,7 +388,9 @@ function createSolvaPayClient(opts) {
332
388
  if (!res.ok) {
333
389
  const error = await res.text();
334
390
  log(`\u274C API Error: ${res.status} - ${error}`);
335
- throw new SolvaPayError2(`List products failed (${res.status}): ${error}`, { status: res.status });
391
+ throw new SolvaPayError2(`List products failed (${res.status}): ${error}`, {
392
+ status: res.status
393
+ });
336
394
  }
337
395
  const result = await res.json();
338
396
  const products = Array.isArray(result) ? result : result.products || [];
@@ -352,7 +410,9 @@ function createSolvaPayClient(opts) {
352
410
  if (!res.ok) {
353
411
  const error = await res.text();
354
412
  log(`\u274C API Error: ${res.status} - ${error}`);
355
- throw new SolvaPayError2(`Create product failed (${res.status}): ${error}`, { status: res.status });
413
+ throw new SolvaPayError2(`Create product failed (${res.status}): ${error}`, {
414
+ status: res.status
415
+ });
356
416
  }
357
417
  const result = await res.json();
358
418
  return result;
@@ -368,7 +428,9 @@ function createSolvaPayClient(opts) {
368
428
  if (!res.ok) {
369
429
  const error = await res.text();
370
430
  log(`\u274C API Error: ${res.status} - ${error}`);
371
- throw new SolvaPayError2(`Bootstrap MCP product failed (${res.status}): ${error}`, { status: res.status });
431
+ throw new SolvaPayError2(`Bootstrap MCP product failed (${res.status}): ${error}`, {
432
+ status: res.status
433
+ });
372
434
  }
373
435
  return await res.json();
374
436
  },
@@ -383,7 +445,9 @@ function createSolvaPayClient(opts) {
383
445
  if (!res.ok) {
384
446
  const error = await res.text();
385
447
  log(`\u274C API Error: ${res.status} - ${error}`);
386
- throw new SolvaPayError2(`Configure MCP plans failed (${res.status}): ${error}`, { status: res.status });
448
+ throw new SolvaPayError2(`Configure MCP plans failed (${res.status}): ${error}`, {
449
+ status: res.status
450
+ });
387
451
  }
388
452
  return await res.json();
389
453
  },
@@ -397,7 +461,9 @@ function createSolvaPayClient(opts) {
397
461
  if (!res.ok && res.status !== 404) {
398
462
  const error = await res.text();
399
463
  log(`\u274C API Error: ${res.status} - ${error}`);
400
- throw new SolvaPayError2(`Delete product failed (${res.status}): ${error}`, { status: res.status });
464
+ throw new SolvaPayError2(`Delete product failed (${res.status}): ${error}`, {
465
+ status: res.status
466
+ });
401
467
  }
402
468
  },
403
469
  // POST: /v1/sdk/products/{productRef}/clone
@@ -411,7 +477,9 @@ function createSolvaPayClient(opts) {
411
477
  if (!res.ok) {
412
478
  const error = await res.text();
413
479
  log(`\u274C API Error: ${res.status} - ${error}`);
414
- throw new SolvaPayError2(`Clone product failed (${res.status}): ${error}`, { status: res.status });
480
+ throw new SolvaPayError2(`Clone product failed (${res.status}): ${error}`, {
481
+ status: res.status
482
+ });
415
483
  }
416
484
  return await res.json();
417
485
  },
@@ -425,7 +493,9 @@ function createSolvaPayClient(opts) {
425
493
  if (!res.ok) {
426
494
  const error = await res.text();
427
495
  log(`\u274C API Error: ${res.status} - ${error}`);
428
- throw new SolvaPayError2(`List plans failed (${res.status}): ${error}`, { status: res.status });
496
+ throw new SolvaPayError2(`List plans failed (${res.status}): ${error}`, {
497
+ status: res.status
498
+ });
429
499
  }
430
500
  const result = await res.json();
431
501
  const plans = Array.isArray(result) ? result : result.plans || [];
@@ -452,7 +522,9 @@ function createSolvaPayClient(opts) {
452
522
  if (!res.ok) {
453
523
  const error = await res.text();
454
524
  log(`\u274C API Error: ${res.status} - ${error}`);
455
- throw new SolvaPayError2(`Create plan failed (${res.status}): ${error}`, { status: res.status });
525
+ throw new SolvaPayError2(`Create plan failed (${res.status}): ${error}`, {
526
+ status: res.status
527
+ });
456
528
  }
457
529
  const result = await res.json();
458
530
  return result;
@@ -468,7 +540,9 @@ function createSolvaPayClient(opts) {
468
540
  if (!res.ok) {
469
541
  const error = await res.text();
470
542
  log(`\u274C API Error: ${res.status} - ${error}`);
471
- throw new SolvaPayError2(`Update plan failed (${res.status}): ${error}`, { status: res.status });
543
+ throw new SolvaPayError2(`Update plan failed (${res.status}): ${error}`, {
544
+ status: res.status
545
+ });
472
546
  }
473
547
  return await res.json();
474
548
  },
@@ -482,7 +556,9 @@ function createSolvaPayClient(opts) {
482
556
  if (!res.ok && res.status !== 404) {
483
557
  const error = await res.text();
484
558
  log(`\u274C API Error: ${res.status} - ${error}`);
485
- throw new SolvaPayError2(`Delete plan failed (${res.status}): ${error}`, { status: res.status });
559
+ throw new SolvaPayError2(`Delete plan failed (${res.status}): ${error}`, {
560
+ status: res.status
561
+ });
486
562
  }
487
563
  },
488
564
  // POST: /payment-intents
@@ -498,13 +574,16 @@ function createSolvaPayClient(opts) {
498
574
  body: JSON.stringify({
499
575
  productRef: params.productRef,
500
576
  planRef: params.planRef,
501
- customerRef: params.customerRef
577
+ customerRef: params.customerRef,
578
+ ...params.currency && { currency: params.currency }
502
579
  })
503
580
  });
504
581
  if (!res.ok) {
505
582
  const error = await res.text();
506
583
  log(`\u274C API Error: ${res.status} - ${error}`);
507
- throw new SolvaPayError2(`Create payment intent failed (${res.status}): ${error}`, { status: res.status });
584
+ throw new SolvaPayError2(`Create payment intent failed (${res.status}): ${error}`, {
585
+ status: res.status
586
+ });
508
587
  }
509
588
  return await res.json();
510
589
  },
@@ -529,7 +608,9 @@ function createSolvaPayClient(opts) {
529
608
  if (!res.ok) {
530
609
  const error = await res.text();
531
610
  log(`\u274C API Error: ${res.status} - ${error}`);
532
- throw new SolvaPayError2(`Create topup payment intent failed (${res.status}): ${error}`, { status: res.status });
611
+ throw new SolvaPayError2(`Create topup payment intent failed (${res.status}): ${error}`, {
612
+ status: res.status
613
+ });
533
614
  }
534
615
  return await res.json();
535
616
  },
@@ -551,7 +632,9 @@ function createSolvaPayClient(opts) {
551
632
  if (!res.ok) {
552
633
  const error = await res.text();
553
634
  log(`\u274C API Error: ${res.status} - ${error}`);
554
- throw new SolvaPayError2(`Process payment failed (${res.status}): ${error}`, { status: res.status });
635
+ throw new SolvaPayError2(`Process payment failed (${res.status}): ${error}`, {
636
+ status: res.status
637
+ });
555
638
  }
556
639
  const result = await res.json();
557
640
  return result;
@@ -579,7 +662,9 @@ function createSolvaPayClient(opts) {
579
662
  { status: 400 }
580
663
  );
581
664
  }
582
- throw new SolvaPayError2(`Cancel purchase failed (${res.status}): ${error}`, { status: res.status });
665
+ throw new SolvaPayError2(`Cancel purchase failed (${res.status}): ${error}`, {
666
+ status: res.status
667
+ });
583
668
  }
584
669
  const responseText = await res.text();
585
670
  let responseData;
@@ -623,12 +708,11 @@ function createSolvaPayClient(opts) {
623
708
  throw new SolvaPayError2(`Purchase not found: ${error}`, { status: 404 });
624
709
  }
625
710
  if (res.status === 400) {
626
- throw new SolvaPayError2(
627
- `Purchase cannot be reactivated: ${error}`,
628
- { status: 400 }
629
- );
711
+ throw new SolvaPayError2(`Purchase cannot be reactivated: ${error}`, { status: 400 });
630
712
  }
631
- throw new SolvaPayError2(`Reactivate purchase failed (${res.status}): ${error}`, { status: res.status });
713
+ throw new SolvaPayError2(`Reactivate purchase failed (${res.status}): ${error}`, {
714
+ status: res.status
715
+ });
632
716
  }
633
717
  const responseText = await res.text();
634
718
  let responseData;
@@ -669,7 +753,9 @@ function createSolvaPayClient(opts) {
669
753
  if (!res.ok) {
670
754
  const error = await res.text();
671
755
  log(`\u274C API Error: ${res.status} - ${error}`);
672
- throw new SolvaPayError2(`Get user info failed (${res.status}): ${error}`, { status: res.status });
756
+ throw new SolvaPayError2(`Get user info failed (${res.status}): ${error}`, {
757
+ status: res.status
758
+ });
673
759
  }
674
760
  return await res.json();
675
761
  },
@@ -683,7 +769,9 @@ function createSolvaPayClient(opts) {
683
769
  if (!res.ok) {
684
770
  const error = await res.text();
685
771
  log(`\u274C API Error: ${res.status} - ${error}`);
686
- throw new SolvaPayError2(`Get customer balance failed (${res.status}): ${error}`, { status: res.status });
772
+ throw new SolvaPayError2(`Get customer balance failed (${res.status}): ${error}`, {
773
+ status: res.status
774
+ });
687
775
  }
688
776
  return await res.json();
689
777
  },
@@ -698,7 +786,9 @@ function createSolvaPayClient(opts) {
698
786
  if (!res.ok) {
699
787
  const error = await res.text();
700
788
  log(`\u274C API Error: ${res.status} - ${error}`);
701
- throw new SolvaPayError2(`Create checkout session failed (${res.status}): ${error}`, { status: res.status });
789
+ throw new SolvaPayError2(`Create checkout session failed (${res.status}): ${error}`, {
790
+ status: res.status
791
+ });
702
792
  }
703
793
  const result = await res.json();
704
794
  return result;
@@ -714,7 +804,9 @@ function createSolvaPayClient(opts) {
714
804
  if (!res.ok) {
715
805
  const error = await res.text();
716
806
  log(`\u274C API Error: ${res.status} - ${error}`);
717
- throw new SolvaPayError2(`Create customer session failed (${res.status}): ${error}`, { status: res.status });
807
+ throw new SolvaPayError2(`Create customer session failed (${res.status}): ${error}`, {
808
+ status: res.status
809
+ });
718
810
  }
719
811
  const result = await res.json();
720
812
  return result;
@@ -730,7 +822,9 @@ function createSolvaPayClient(opts) {
730
822
  if (!res.ok) {
731
823
  const error = await res.text();
732
824
  log(`\u274C API Error: ${res.status} - ${error}`);
733
- throw new SolvaPayError2(`Activate plan failed (${res.status}): ${error}`, { status: res.status });
825
+ throw new SolvaPayError2(`Activate plan failed (${res.status}): ${error}`, {
826
+ status: res.status
827
+ });
734
828
  }
735
829
  return await res.json();
736
830
  },
@@ -741,7 +835,9 @@ function createSolvaPayClient(opts) {
741
835
  if (!res.ok) {
742
836
  const error = await res.text();
743
837
  log(`\u274C API Error: ${res.status} - ${error}`);
744
- throw new SolvaPayError2(`Get payment method failed (${res.status}): ${error}`, { status: res.status });
838
+ throw new SolvaPayError2(`Get payment method failed (${res.status}): ${error}`, {
839
+ status: res.status
840
+ });
745
841
  }
746
842
  return await res.json();
747
843
  }
@@ -2016,6 +2112,12 @@ function createSolvaPay(config) {
2016
2112
  trackUsage(params) {
2017
2113
  return apiClient.trackUsage(params);
2018
2114
  },
2115
+ trackUsageBulk(params) {
2116
+ if (!apiClient.trackUsageBulk) {
2117
+ throw new SolvaPayError3("trackUsageBulk is not available on this API client");
2118
+ }
2119
+ return apiClient.trackUsageBulk(params);
2120
+ },
2019
2121
  createCustomer(params) {
2020
2122
  if (!apiClient.createCustomer) {
2021
2123
  throw new SolvaPayError3("createCustomer is not available on this API client");
@@ -2025,6 +2127,12 @@ function createSolvaPay(config) {
2025
2127
  getCustomer(params) {
2026
2128
  return apiClient.getCustomer(params);
2027
2129
  },
2130
+ assignCredits(params) {
2131
+ if (!apiClient.assignCredits) {
2132
+ throw new SolvaPayError3("assignCredits is not available on this API client");
2133
+ }
2134
+ return apiClient.assignCredits(params);
2135
+ },
2028
2136
  getCustomerBalance(params) {
2029
2137
  if (!apiClient.getCustomerBalance) {
2030
2138
  throw new SolvaPayError3("getCustomerBalance is not available on this API client");
@@ -2110,7 +2218,9 @@ function createSolvaPay(config) {
2110
2218
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2111
2219
  async function(businessLogic) {
2112
2220
  const getCustomerRef = (args) => {
2113
- const configuredRef = options.getCustomerRef?.(args);
2221
+ const configuredRef = options.getCustomerRef?.(
2222
+ args
2223
+ );
2114
2224
  if (typeof configuredRef === "string") {
2115
2225
  return configuredRef;
2116
2226
  }
@@ -2129,9 +2239,7 @@ function createSolvaPay(config) {
2129
2239
  );
2130
2240
  if (decision.outcome === "gate") {
2131
2241
  const errorMessage = decision.gate.kind === "activation_required" ? "Activation required" : "Payment required";
2132
- const body = paywallErrorToClientPayload(
2133
- new PaywallError(errorMessage, decision.gate)
2134
- );
2242
+ const body = paywallErrorToClientPayload(new PaywallError(errorMessage, decision.gate));
2135
2243
  const response = new Response(JSON.stringify(body), {
2136
2244
  status: 402,
2137
2245
  headers: { "content-type": "application/json" }
@@ -2258,7 +2366,8 @@ async function createPaymentIntentCore(request, body, options = {}) {
2258
2366
  const paymentIntent = await solvaPay.createPaymentIntent({
2259
2367
  productRef: body.productRef,
2260
2368
  planRef: body.planRef,
2261
- customerRef
2369
+ customerRef,
2370
+ ...body.currency && { currency: body.currency }
2262
2371
  });
2263
2372
  return {
2264
2373
  processorPaymentId: paymentIntent.processorPaymentId,
@@ -2788,15 +2897,16 @@ async function trackUsageCore(request, body, options = {}) {
2788
2897
  email: email || void 0,
2789
2898
  name: name || void 0
2790
2899
  });
2791
- await solvaPay.trackUsage({
2900
+ const result = await solvaPay.trackUsage({
2792
2901
  customerRef,
2793
2902
  actionType: body.actionType,
2794
2903
  units: body.units,
2795
2904
  productRef: body.productRef,
2796
2905
  description: body.description,
2797
- metadata: body.metadata
2906
+ metadata: body.metadata,
2907
+ idempotencyKey: body.idempotencyKey
2798
2908
  });
2799
- return { success: true };
2909
+ return result;
2800
2910
  } catch (error) {
2801
2911
  return handleRouteError(error, "Track usage", "Track usage failed");
2802
2912
  }