@solvapay/server 1.3.0 → 1.4.0-preview-e2cd9bda9dee33e68f6bba7098f7d683e6f1b742

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/edge.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import * as _solvapay_core from '@solvapay/core';
2
+ import { BusinessDetailsInput, TaxBreakdown } from '@solvapay/core';
3
+
1
4
  interface components {
2
5
  schemas: {
3
6
  SdkMerchantResponseDto: {
@@ -243,6 +246,28 @@ interface components {
243
246
  customerRef: string;
244
247
  planRef?: string;
245
248
  };
249
+ BusinessDetailsDto: {
250
+ /** Whether the purchase is on behalf of a business */
251
+ isBusiness: boolean;
252
+ /** Legal business name */
253
+ businessName?: string;
254
+ /** ISO 3166-1 alpha-2 country code */
255
+ country?: string;
256
+ /** Tax / VAT identification number */
257
+ taxId?: string;
258
+ };
259
+ TaxBreakdownResponse: {
260
+ subtotal: number;
261
+ taxAmount: number;
262
+ taxRate: number;
263
+ treatment: "reverse_charge" | "standard" | "none" | "not_collecting";
264
+ total: number;
265
+ currency: string;
266
+ inclusive: boolean;
267
+ };
268
+ AttachBusinessDetailsResponse: {
269
+ taxBreakdown: components["schemas"]["TaxBreakdownResponse"];
270
+ };
246
271
  CreateCheckoutSessionResponse: {
247
272
  /**
248
273
  * Checkout session ID/token
@@ -403,6 +428,11 @@ interface components {
403
428
  createdAt: string;
404
429
  /** @description Last update timestamp */
405
430
  updatedAt: string;
431
+ /**
432
+ * Tax inclusion behavior for business checkout
433
+ * @enum {string}
434
+ */
435
+ taxBehavior?: "auto" | "inclusive" | "exclusive";
406
436
  };
407
437
  CreatePlanRequest: {
408
438
  name: string;
@@ -450,6 +480,8 @@ interface components {
450
480
  maxActiveUsers?: number;
451
481
  accessExpiryDays?: number;
452
482
  default?: boolean;
483
+ /** @enum {string} */
484
+ taxBehavior?: "auto" | "inclusive" | "exclusive";
453
485
  };
454
486
  UpdatePlanRequest: {
455
487
  name?: string;
@@ -484,6 +516,8 @@ interface components {
484
516
  [key: string]: unknown;
485
517
  };
486
518
  default?: boolean;
519
+ /** @enum {string} */
520
+ taxBehavior?: "auto" | "inclusive" | "exclusive";
487
521
  };
488
522
  CreateProductRequest: {
489
523
  name: string;
@@ -1673,6 +1707,51 @@ interface operations {
1673
1707
  };
1674
1708
  };
1675
1709
  };
1710
+ PaymentIntentSdkController_attachBusinessDetails: {
1711
+ parameters: {
1712
+ query?: never;
1713
+ header?: never;
1714
+ path: {
1715
+ /** @description Stripe payment intent ID */
1716
+ processorPaymentId: string;
1717
+ };
1718
+ cookie?: never;
1719
+ };
1720
+ requestBody: {
1721
+ content: {
1722
+ "application/json": components["schemas"]["BusinessDetailsDto"];
1723
+ };
1724
+ };
1725
+ responses: {
1726
+ /** @description Tax breakdown after applying business details */
1727
+ 200: {
1728
+ headers: {
1729
+ [name: string]: unknown;
1730
+ };
1731
+ content: {
1732
+ "application/json": components["schemas"]["AttachBusinessDetailsResponse"];
1733
+ };
1734
+ };
1735
+ /** @description Invalid business details or payment intent state */
1736
+ 400: {
1737
+ headers: {
1738
+ [name: string]: unknown;
1739
+ };
1740
+ content: {
1741
+ "application/json": unknown;
1742
+ };
1743
+ };
1744
+ /** @description Payment intent not found */
1745
+ 404: {
1746
+ headers: {
1747
+ [name: string]: unknown;
1748
+ };
1749
+ content: {
1750
+ "application/json": unknown;
1751
+ };
1752
+ };
1753
+ };
1754
+ };
1676
1755
  CheckoutSessionSdkController_createCheckoutSession: {
1677
1756
  parameters: {
1678
1757
  query?: never;
@@ -2999,6 +3078,13 @@ type WebhookEvent = {
2999
3078
  * Types related to the SolvaPay API client and backend communication.
3000
3079
  */
3001
3080
 
3081
+ type AttachBusinessDetailsParams = {
3082
+ paymentIntentId: string;
3083
+ customerRef?: string;
3084
+ } & BusinessDetailsInput;
3085
+ type AttachBusinessDetailsResult = {
3086
+ taxBreakdown: TaxBreakdown;
3087
+ };
3002
3088
  type CheckLimitsRequest = components['schemas']['CheckLimitRequest'] & {
3003
3089
  /**
3004
3090
  * When `true`, the backend mints a checkout session (or customer
@@ -3381,6 +3467,7 @@ interface SolvaPayClient {
3381
3467
  customerRef: string;
3382
3468
  planRef?: string;
3383
3469
  }): Promise<ProcessPaymentResult>;
3470
+ attachBusinessDetails?(params: AttachBusinessDetailsParams): Promise<AttachBusinessDetailsResult>;
3384
3471
  getUserInfo?(params: {
3385
3472
  customerRef: string;
3386
3473
  productRef: string;
@@ -4174,6 +4261,21 @@ interface SolvaPay {
4174
4261
  customerRef: string;
4175
4262
  planRef?: string;
4176
4263
  }): Promise<ProcessPaymentResult>;
4264
+ /**
4265
+ * Attach business purchase details to a payment intent
4266
+ * and retrieve the computed tax breakdown.
4267
+ */
4268
+ attachBusinessDetails(params: {
4269
+ paymentIntentId: string;
4270
+ customerRef?: string;
4271
+ isBusiness: boolean;
4272
+ businessName?: string;
4273
+ country?: string;
4274
+ taxId?: string;
4275
+ taxIdType?: _solvapay_core.TaxIdType;
4276
+ }): Promise<{
4277
+ taxBreakdown: _solvapay_core.TaxBreakdown;
4278
+ }>;
4177
4279
  /**
4178
4280
  * Check if customer is within usage limits for a product.
4179
4281
  *
@@ -5103,6 +5205,21 @@ declare function processPaymentIntentCore(request: Request, body: {
5103
5205
  * }
5104
5206
  * ```
5105
5207
  */
5208
+ /**
5209
+ * Attach business purchase details to a credit-topup payment intent and
5210
+ * retrieve the computed tax breakdown.
5211
+ *
5212
+ * Validates business fields client-side via `@solvapay/core` before
5213
+ * forwarding to the SolvaPay backend.
5214
+ */
5215
+ declare function attachBusinessDetailsCore(request: Request, body: {
5216
+ paymentIntentId: string;
5217
+ customerRef?: string;
5218
+ } & BusinessDetailsInput, options?: {
5219
+ solvaPay?: SolvaPay;
5220
+ }): Promise<{
5221
+ taxBreakdown: TaxBreakdown;
5222
+ } | ErrorResult>;
5106
5223
  declare function processTopupPaymentIntentCore(request: Request, body: {
5107
5224
  paymentIntentId: string;
5108
5225
  }, options?: {
@@ -5384,4 +5501,4 @@ declare function verifyWebhook({ body, signature, secret, }: {
5384
5501
  secret: string;
5385
5502
  }): Promise<WebhookEvent>;
5386
5503
 
5387
- export { type ActivatePlanResult, type AuthenticatedUser, type ConfigureMcpPlansRequest, type ConfigureMcpPlansResponse, type CreateSolvaPayConfig, type CustomerBalanceResult, type CustomerResponseMapped, type CustomerWebhookObject, type ErrorResult, type GetUsageResult, type HttpAdapterOptions, type LimitActivationBalance, type LimitActivationProduct, type LimitPlanSummary, type LimitResponseWithPlan, type McpBootstrapPlanInput, type McpBootstrapRequest, type McpBootstrapResponse, type McpToolPlanMappingInput, type NextAdapterOptions, type OneTimePurchaseInfo, type PayableAllowResult, type PayableFunction, type PayableGateOptions, type PayableGateResult, type PayableOptions, type PayablePaywallResult, type PaymentMethodInfo, type PaywallArgs, type PaywallDecision, PaywallError, type PaywallMetadata, type PaywallState, type PaywallStructuredContent, type ProcessPaymentResult, type PurchaseCheckResult, type RetryOptions, type SdkMerchantResponse, type SdkProductResponse, type ServerClientOptions, type SolvaPay, type SolvaPayClient, type ToolPlanMappingInput, type TopupProcessResult, type WebhookEvent, type WebhookEventForType, type WebhookEventObjectMap, type WebhookEventType, type WebhookProduct, activatePlanCore, buildGateMessage, buildNudgeMessage, buildPaywallGate, cancelPurchaseCore, checkLimitsCore, checkPurchaseCore, classifyPaywallState, type components, createCheckoutSessionCore, createCustomerSessionCore, createPaymentIntentCore, createSolvaPay, createSolvaPayClient, createTopupPaymentIntentCore, disableAutoRechargeCore, getAuthenticatedUserCore, getAutoRechargeCore, getCustomerBalanceCore, getMerchantCore, getPaymentMethodCore, getProductCore, getUsageCore, handleRouteError, isErrorResult, isPaywallStructuredContent, listPlansCore, paywallErrorToClientPayload, processPaymentIntentCore, processTopupPaymentIntentCore, reactivatePurchaseCore, saveAutoRechargeCore, syncCustomerCore, trackUsageCore, verifyWebhook, withRetry };
5504
+ export { type ActivatePlanResult, type AuthenticatedUser, type ConfigureMcpPlansRequest, type ConfigureMcpPlansResponse, type CreateSolvaPayConfig, type CustomerBalanceResult, type CustomerResponseMapped, type CustomerWebhookObject, type ErrorResult, type GetUsageResult, type HttpAdapterOptions, type LimitActivationBalance, type LimitActivationProduct, type LimitPlanSummary, type LimitResponseWithPlan, type McpBootstrapPlanInput, type McpBootstrapRequest, type McpBootstrapResponse, type McpToolPlanMappingInput, type NextAdapterOptions, type OneTimePurchaseInfo, type PayableAllowResult, type PayableFunction, type PayableGateOptions, type PayableGateResult, type PayableOptions, type PayablePaywallResult, type PaymentMethodInfo, type PaywallArgs, type PaywallDecision, PaywallError, type PaywallMetadata, type PaywallState, type PaywallStructuredContent, type ProcessPaymentResult, type PurchaseCheckResult, type RetryOptions, type SdkMerchantResponse, type SdkProductResponse, type ServerClientOptions, type SolvaPay, type SolvaPayClient, type ToolPlanMappingInput, type TopupProcessResult, type WebhookEvent, type WebhookEventForType, type WebhookEventObjectMap, type WebhookEventType, type WebhookProduct, activatePlanCore, attachBusinessDetailsCore, buildGateMessage, buildNudgeMessage, buildPaywallGate, cancelPurchaseCore, checkLimitsCore, checkPurchaseCore, classifyPaywallState, type components, createCheckoutSessionCore, createCustomerSessionCore, createPaymentIntentCore, createSolvaPay, createSolvaPayClient, createTopupPaymentIntentCore, disableAutoRechargeCore, getAuthenticatedUserCore, getAutoRechargeCore, getCustomerBalanceCore, getMerchantCore, getPaymentMethodCore, getProductCore, getUsageCore, handleRouteError, isErrorResult, isPaywallStructuredContent, listPlansCore, paywallErrorToClientPayload, processPaymentIntentCore, processTopupPaymentIntentCore, reactivatePurchaseCore, saveAutoRechargeCore, syncCustomerCore, trackUsageCore, verifyWebhook, withRetry };
package/dist/edge.js CHANGED
@@ -489,6 +489,31 @@ function createSolvaPayClient(opts) {
489
489
  const result = await res.json();
490
490
  return result;
491
491
  },
492
+ // POST: /v1/sdk/payment-intents/{paymentIntentId}/business-details
493
+ async attachBusinessDetails(params) {
494
+ const url = `${base}/v1/sdk/payment-intents/${params.paymentIntentId}/business-details`;
495
+ const res = await fetch(url, {
496
+ method: "POST",
497
+ headers,
498
+ body: JSON.stringify({
499
+ isBusiness: params.isBusiness,
500
+ ...params.businessName !== void 0 && { businessName: params.businessName },
501
+ ...params.country !== void 0 && { country: params.country },
502
+ ...params.taxId !== void 0 && { taxId: params.taxId },
503
+ ...params.taxIdType !== void 0 && { taxIdType: params.taxIdType },
504
+ ...params.customerRef !== void 0 && { customerRef: params.customerRef }
505
+ })
506
+ });
507
+ if (!res.ok) {
508
+ const error = await res.text();
509
+ log(`\u274C API Error: ${res.status} - ${error}`);
510
+ throw new SolvaPayError(
511
+ `Attach business details failed (${res.status}): ${error}`,
512
+ { status: res.status }
513
+ );
514
+ }
515
+ return await res.json();
516
+ },
492
517
  // POST: /v1/sdk/purchases/{purchaseRef}/cancel
493
518
  async cancelPurchase(params) {
494
519
  const url = `${base}/v1/sdk/purchases/${params.purchaseRef}/cancel`;
@@ -2011,6 +2036,14 @@ function createSolvaPay(config) {
2011
2036
  }
2012
2037
  return apiClient.processPaymentIntent(params);
2013
2038
  },
2039
+ attachBusinessDetails(params) {
2040
+ if (!apiClient.attachBusinessDetails) {
2041
+ throw new SolvaPayError2(
2042
+ "attachBusinessDetails is not available on this API client"
2043
+ );
2044
+ }
2045
+ return apiClient.attachBusinessDetails(params);
2046
+ },
2014
2047
  checkLimits(params) {
2015
2048
  return apiClient.checkLimits(params);
2016
2049
  },
@@ -2412,6 +2445,11 @@ async function getCustomerBalanceCore(request, options = {}) {
2412
2445
  }
2413
2446
  }
2414
2447
 
2448
+ // src/helpers/payment.ts
2449
+ import {
2450
+ validateBusinessDetails
2451
+ } from "@solvapay/core";
2452
+
2415
2453
  // src/helpers/balance-poll.ts
2416
2454
  var TOPUP_BALANCE_POLL_DELAYS_MS = [500, 1e3, 2e3, 4e3];
2417
2455
  var BALANCE_RECONCILE_DELAYS_MS = [500, 1e3, 2e3, 4e3, 8e3, 16e3];
@@ -2544,6 +2582,50 @@ async function processPaymentIntentCore(request, body, options = {}) {
2544
2582
  return handleRouteError(error, "Process payment intent", "Payment processing failed");
2545
2583
  }
2546
2584
  }
2585
+ async function attachBusinessDetailsCore(request, body, options = {}) {
2586
+ try {
2587
+ if (!body.paymentIntentId) {
2588
+ return {
2589
+ error: "paymentIntentId is required",
2590
+ status: 400
2591
+ };
2592
+ }
2593
+ const validation = validateBusinessDetails({
2594
+ isBusiness: body.isBusiness,
2595
+ businessName: body.businessName,
2596
+ country: body.country,
2597
+ taxId: body.taxId,
2598
+ taxIdType: body.taxIdType
2599
+ });
2600
+ if (!validation.success) {
2601
+ const firstIssue = validation.error.issues[0];
2602
+ return {
2603
+ error: firstIssue?.message ?? "Invalid business details",
2604
+ status: 400
2605
+ };
2606
+ }
2607
+ const solvaPay = options.solvaPay || createSolvaPay();
2608
+ if (typeof solvaPay.attachBusinessDetails !== "function") {
2609
+ return {
2610
+ error: "attachBusinessDetails is not available on this SolvaPay client",
2611
+ status: 501
2612
+ };
2613
+ }
2614
+ const details = validation.data;
2615
+ const result = await solvaPay.attachBusinessDetails({
2616
+ paymentIntentId: body.paymentIntentId,
2617
+ ...body.customerRef !== void 0 && { customerRef: body.customerRef },
2618
+ ...details
2619
+ });
2620
+ return result;
2621
+ } catch (error) {
2622
+ return handleRouteError(
2623
+ error,
2624
+ "Attach business details",
2625
+ "Failed to attach business details"
2626
+ );
2627
+ }
2628
+ }
2547
2629
  async function processTopupPaymentIntentCore(request, body, options = {}) {
2548
2630
  try {
2549
2631
  if (!body.paymentIntentId) {
@@ -3224,6 +3306,7 @@ async function verifyWebhook({
3224
3306
  export {
3225
3307
  PaywallError,
3226
3308
  activatePlanCore,
3309
+ attachBusinessDetailsCore,
3227
3310
  buildGateMessage,
3228
3311
  buildNudgeMessage,
3229
3312
  buildPaywallGate,
@@ -693,6 +693,31 @@ function createSolvaPayClient(opts) {
693
693
  const result = await res.json();
694
694
  return result;
695
695
  },
696
+ // POST: /v1/sdk/payment-intents/{paymentIntentId}/business-details
697
+ async attachBusinessDetails(params) {
698
+ const url = `${base}/v1/sdk/payment-intents/${params.paymentIntentId}/business-details`;
699
+ const res = await fetch(url, {
700
+ method: "POST",
701
+ headers,
702
+ body: JSON.stringify({
703
+ isBusiness: params.isBusiness,
704
+ ...params.businessName !== void 0 && { businessName: params.businessName },
705
+ ...params.country !== void 0 && { country: params.country },
706
+ ...params.taxId !== void 0 && { taxId: params.taxId },
707
+ ...params.taxIdType !== void 0 && { taxIdType: params.taxIdType },
708
+ ...params.customerRef !== void 0 && { customerRef: params.customerRef }
709
+ })
710
+ });
711
+ if (!res.ok) {
712
+ const error = await res.text();
713
+ log(`\u274C API Error: ${res.status} - ${error}`);
714
+ throw new import_core2.SolvaPayError(
715
+ `Attach business details failed (${res.status}): ${error}`,
716
+ { status: res.status }
717
+ );
718
+ }
719
+ return await res.json();
720
+ },
696
721
  // POST: /v1/sdk/purchases/{purchaseRef}/cancel
697
722
  async cancelPurchase(params) {
698
723
  const url = `${base}/v1/sdk/purchases/${params.purchaseRef}/cancel`;
@@ -2201,6 +2226,14 @@ function createSolvaPay(config) {
2201
2226
  }
2202
2227
  return apiClient.processPaymentIntent(params);
2203
2228
  },
2229
+ attachBusinessDetails(params) {
2230
+ if (!apiClient.attachBusinessDetails) {
2231
+ throw new import_core3.SolvaPayError(
2232
+ "attachBusinessDetails is not available on this API client"
2233
+ );
2234
+ }
2235
+ return apiClient.attachBusinessDetails(params);
2236
+ },
2204
2237
  checkLimits(params) {
2205
2238
  return apiClient.checkLimits(params);
2206
2239
  },
@@ -2440,6 +2473,7 @@ async function getCustomerBalanceCore(request, options = {}) {
2440
2473
  }
2441
2474
 
2442
2475
  // src/helpers/payment.ts
2476
+ var import_core4 = require("@solvapay/core");
2443
2477
  async function createPaymentIntentCore(request, body, options = {}) {
2444
2478
  try {
2445
2479
  if (!body.planRef || !body.productRef) {
@@ -2618,7 +2652,7 @@ async function createCustomerSessionCore(request, options = {}) {
2618
2652
  }
2619
2653
 
2620
2654
  // src/helpers/renewal.ts
2621
- var import_core4 = require("@solvapay/core");
2655
+ var import_core5 = require("@solvapay/core");
2622
2656
  async function cancelPurchaseCore(request, body, options = {}) {
2623
2657
  try {
2624
2658
  if (!body.purchaseRef) {
@@ -2664,7 +2698,7 @@ async function cancelPurchaseCore(request, body, options = {}) {
2664
2698
  await new Promise((resolve) => setTimeout(resolve, 500));
2665
2699
  return cancelledPurchase;
2666
2700
  } catch (error) {
2667
- if (error instanceof import_core4.SolvaPayError) {
2701
+ if (error instanceof import_core5.SolvaPayError) {
2668
2702
  const errorMessage = error.message;
2669
2703
  if (errorMessage.includes("not found")) {
2670
2704
  return {
@@ -2732,7 +2766,7 @@ async function reactivatePurchaseCore(request, body, options = {}) {
2732
2766
  await new Promise((resolve) => setTimeout(resolve, 500));
2733
2767
  return reactivatedPurchase;
2734
2768
  } catch (error) {
2735
- if (error instanceof import_core4.SolvaPayError) {
2769
+ if (error instanceof import_core5.SolvaPayError) {
2736
2770
  const errorMessage = error.message;
2737
2771
  if (errorMessage.includes("not found")) {
2738
2772
  return {
@@ -2813,7 +2847,7 @@ async function getPaymentMethodCore(request, options = {}) {
2813
2847
  }
2814
2848
 
2815
2849
  // src/helpers/plans.ts
2816
- var import_core5 = require("@solvapay/core");
2850
+ var import_core6 = require("@solvapay/core");
2817
2851
  async function listPlansCore(request, options = {}) {
2818
2852
  try {
2819
2853
  const url = new URL(request.url);
@@ -2825,7 +2859,7 @@ async function listPlansCore(request, options = {}) {
2825
2859
  };
2826
2860
  }
2827
2861
  const apiClient = options.solvaPay?.apiClient ?? (() => {
2828
- const config = (0, import_core5.getSolvaPayConfig)();
2862
+ const config = (0, import_core6.getSolvaPayConfig)();
2829
2863
  if (!config.apiKey) return null;
2830
2864
  return createSolvaPayClient({
2831
2865
  apiKey: config.apiKey,
@@ -2855,11 +2889,11 @@ async function listPlansCore(request, options = {}) {
2855
2889
  }
2856
2890
 
2857
2891
  // src/helpers/merchant.ts
2858
- var import_core6 = require("@solvapay/core");
2892
+ var import_core7 = require("@solvapay/core");
2859
2893
  async function getMerchantCore(_request, options = {}) {
2860
2894
  try {
2861
2895
  const apiClient = options.solvaPay?.apiClient ?? (() => {
2862
- const config = (0, import_core6.getSolvaPayConfig)();
2896
+ const config = (0, import_core7.getSolvaPayConfig)();
2863
2897
  if (!config.apiKey) return null;
2864
2898
  return createSolvaPayClient({
2865
2899
  apiKey: config.apiKey,
@@ -2886,7 +2920,7 @@ async function getMerchantCore(_request, options = {}) {
2886
2920
  }
2887
2921
 
2888
2922
  // src/helpers/product.ts
2889
- var import_core7 = require("@solvapay/core");
2923
+ var import_core8 = require("@solvapay/core");
2890
2924
  async function getProductCore(request, options = {}) {
2891
2925
  try {
2892
2926
  const url = new URL(request.url);
@@ -2898,7 +2932,7 @@ async function getProductCore(request, options = {}) {
2898
2932
  };
2899
2933
  }
2900
2934
  const apiClient = options.solvaPay?.apiClient ?? (() => {
2901
- const config = (0, import_core7.getSolvaPayConfig)();
2935
+ const config = (0, import_core8.getSolvaPayConfig)();
2902
2936
  if (!config.apiKey) return null;
2903
2937
  return createSolvaPayClient({
2904
2938
  apiKey: config.apiKey,
@@ -3009,7 +3043,7 @@ async function trackUsageCore(request, body, options = {}) {
3009
3043
  }
3010
3044
 
3011
3045
  // src/edge.ts
3012
- var import_core8 = require("@solvapay/core");
3046
+ var import_core9 = require("@solvapay/core");
3013
3047
  function timingSafeEqual(a, b) {
3014
3048
  if (a.length !== b.length) return false;
3015
3049
  let mismatch = 0;
@@ -3024,22 +3058,22 @@ async function verifyWebhook({
3024
3058
  secret
3025
3059
  }) {
3026
3060
  const toleranceSec = 300;
3027
- if (!signature) throw new import_core8.SolvaPayError("Missing webhook signature");
3061
+ if (!signature) throw new import_core9.SolvaPayError("Missing webhook signature");
3028
3062
  const parts = signature.split(",");
3029
3063
  const tPart = parts.find((p) => p.startsWith("t="));
3030
3064
  const v1Part = parts.find((p) => p.startsWith("v1="));
3031
3065
  if (!tPart || !v1Part) {
3032
- throw new import_core8.SolvaPayError("Malformed webhook signature");
3066
+ throw new import_core9.SolvaPayError("Malformed webhook signature");
3033
3067
  }
3034
3068
  const timestamp = parseInt(tPart.slice(2), 10);
3035
3069
  const receivedHmac = v1Part.slice(3);
3036
3070
  if (Number.isNaN(timestamp) || !receivedHmac) {
3037
- throw new import_core8.SolvaPayError("Malformed webhook signature");
3071
+ throw new import_core9.SolvaPayError("Malformed webhook signature");
3038
3072
  }
3039
3073
  if (toleranceSec > 0) {
3040
3074
  const age = Math.abs(Math.floor(Date.now() / 1e3) - timestamp);
3041
3075
  if (age > toleranceSec) {
3042
- throw new import_core8.SolvaPayError("Webhook signature timestamp too old");
3076
+ throw new import_core9.SolvaPayError("Webhook signature timestamp too old");
3043
3077
  }
3044
3078
  }
3045
3079
  const enc = new TextEncoder();
@@ -3053,12 +3087,12 @@ async function verifyWebhook({
3053
3087
  const sigBuf = await crypto.subtle.sign("HMAC", key, enc.encode(`${timestamp}.${body}`));
3054
3088
  const expectedHmac = Array.from(new Uint8Array(sigBuf)).map((b) => b.toString(16).padStart(2, "0")).join("");
3055
3089
  if (!timingSafeEqual(expectedHmac, receivedHmac)) {
3056
- throw new import_core8.SolvaPayError("Invalid webhook signature");
3090
+ throw new import_core9.SolvaPayError("Invalid webhook signature");
3057
3091
  }
3058
3092
  try {
3059
3093
  return JSON.parse(body);
3060
3094
  } catch {
3061
- throw new import_core8.SolvaPayError("Invalid webhook payload: body is not valid JSON");
3095
+ throw new import_core9.SolvaPayError("Invalid webhook payload: body is not valid JSON");
3062
3096
  }
3063
3097
  }
3064
3098
 
@@ -243,6 +243,28 @@ interface components {
243
243
  customerRef: string;
244
244
  planRef?: string;
245
245
  };
246
+ BusinessDetailsDto: {
247
+ /** Whether the purchase is on behalf of a business */
248
+ isBusiness: boolean;
249
+ /** Legal business name */
250
+ businessName?: string;
251
+ /** ISO 3166-1 alpha-2 country code */
252
+ country?: string;
253
+ /** Tax / VAT identification number */
254
+ taxId?: string;
255
+ };
256
+ TaxBreakdownResponse: {
257
+ subtotal: number;
258
+ taxAmount: number;
259
+ taxRate: number;
260
+ treatment: "reverse_charge" | "standard" | "none" | "not_collecting";
261
+ total: number;
262
+ currency: string;
263
+ inclusive: boolean;
264
+ };
265
+ AttachBusinessDetailsResponse: {
266
+ taxBreakdown: components["schemas"]["TaxBreakdownResponse"];
267
+ };
246
268
  CreateCheckoutSessionResponse: {
247
269
  /**
248
270
  * Checkout session ID/token
@@ -403,6 +425,11 @@ interface components {
403
425
  createdAt: string;
404
426
  /** @description Last update timestamp */
405
427
  updatedAt: string;
428
+ /**
429
+ * Tax inclusion behavior for business checkout
430
+ * @enum {string}
431
+ */
432
+ taxBehavior?: "auto" | "inclusive" | "exclusive";
406
433
  };
407
434
  CreatePlanRequest: {
408
435
  name: string;
@@ -450,6 +477,8 @@ interface components {
450
477
  maxActiveUsers?: number;
451
478
  accessExpiryDays?: number;
452
479
  default?: boolean;
480
+ /** @enum {string} */
481
+ taxBehavior?: "auto" | "inclusive" | "exclusive";
453
482
  };
454
483
  UpdatePlanRequest: {
455
484
  name?: string;
@@ -484,6 +513,8 @@ interface components {
484
513
  [key: string]: unknown;
485
514
  };
486
515
  default?: boolean;
516
+ /** @enum {string} */
517
+ taxBehavior?: "auto" | "inclusive" | "exclusive";
487
518
  };
488
519
  CreateProductRequest: {
489
520
  name: string;
@@ -243,6 +243,28 @@ interface components {
243
243
  customerRef: string;
244
244
  planRef?: string;
245
245
  };
246
+ BusinessDetailsDto: {
247
+ /** Whether the purchase is on behalf of a business */
248
+ isBusiness: boolean;
249
+ /** Legal business name */
250
+ businessName?: string;
251
+ /** ISO 3166-1 alpha-2 country code */
252
+ country?: string;
253
+ /** Tax / VAT identification number */
254
+ taxId?: string;
255
+ };
256
+ TaxBreakdownResponse: {
257
+ subtotal: number;
258
+ taxAmount: number;
259
+ taxRate: number;
260
+ treatment: "reverse_charge" | "standard" | "none" | "not_collecting";
261
+ total: number;
262
+ currency: string;
263
+ inclusive: boolean;
264
+ };
265
+ AttachBusinessDetailsResponse: {
266
+ taxBreakdown: components["schemas"]["TaxBreakdownResponse"];
267
+ };
246
268
  CreateCheckoutSessionResponse: {
247
269
  /**
248
270
  * Checkout session ID/token
@@ -403,6 +425,11 @@ interface components {
403
425
  createdAt: string;
404
426
  /** @description Last update timestamp */
405
427
  updatedAt: string;
428
+ /**
429
+ * Tax inclusion behavior for business checkout
430
+ * @enum {string}
431
+ */
432
+ taxBehavior?: "auto" | "inclusive" | "exclusive";
406
433
  };
407
434
  CreatePlanRequest: {
408
435
  name: string;
@@ -450,6 +477,8 @@ interface components {
450
477
  maxActiveUsers?: number;
451
478
  accessExpiryDays?: number;
452
479
  default?: boolean;
480
+ /** @enum {string} */
481
+ taxBehavior?: "auto" | "inclusive" | "exclusive";
453
482
  };
454
483
  UpdatePlanRequest: {
455
484
  name?: string;
@@ -484,6 +513,8 @@ interface components {
484
513
  [key: string]: unknown;
485
514
  };
486
515
  default?: boolean;
516
+ /** @enum {string} */
517
+ taxBehavior?: "auto" | "inclusive" | "exclusive";
487
518
  };
488
519
  CreateProductRequest: {
489
520
  name: string;
@@ -640,6 +640,31 @@ function createSolvaPayClient(opts) {
640
640
  const result = await res.json();
641
641
  return result;
642
642
  },
643
+ // POST: /v1/sdk/payment-intents/{paymentIntentId}/business-details
644
+ async attachBusinessDetails(params) {
645
+ const url = `${base}/v1/sdk/payment-intents/${params.paymentIntentId}/business-details`;
646
+ const res = await fetch(url, {
647
+ method: "POST",
648
+ headers,
649
+ body: JSON.stringify({
650
+ isBusiness: params.isBusiness,
651
+ ...params.businessName !== void 0 && { businessName: params.businessName },
652
+ ...params.country !== void 0 && { country: params.country },
653
+ ...params.taxId !== void 0 && { taxId: params.taxId },
654
+ ...params.taxIdType !== void 0 && { taxIdType: params.taxIdType },
655
+ ...params.customerRef !== void 0 && { customerRef: params.customerRef }
656
+ })
657
+ });
658
+ if (!res.ok) {
659
+ const error = await res.text();
660
+ log(`\u274C API Error: ${res.status} - ${error}`);
661
+ throw new SolvaPayError2(
662
+ `Attach business details failed (${res.status}): ${error}`,
663
+ { status: res.status }
664
+ );
665
+ }
666
+ return await res.json();
667
+ },
643
668
  // POST: /v1/sdk/purchases/{purchaseRef}/cancel
644
669
  async cancelPurchase(params) {
645
670
  const url = `${base}/v1/sdk/purchases/${params.purchaseRef}/cancel`;
@@ -2148,6 +2173,14 @@ function createSolvaPay(config) {
2148
2173
  }
2149
2174
  return apiClient.processPaymentIntent(params);
2150
2175
  },
2176
+ attachBusinessDetails(params) {
2177
+ if (!apiClient.attachBusinessDetails) {
2178
+ throw new SolvaPayError3(
2179
+ "attachBusinessDetails is not available on this API client"
2180
+ );
2181
+ }
2182
+ return apiClient.attachBusinessDetails(params);
2183
+ },
2151
2184
  checkLimits(params) {
2152
2185
  return apiClient.checkLimits(params);
2153
2186
  },
@@ -2387,6 +2420,9 @@ async function getCustomerBalanceCore(request, options = {}) {
2387
2420
  }
2388
2421
 
2389
2422
  // src/helpers/payment.ts
2423
+ import {
2424
+ validateBusinessDetails
2425
+ } from "@solvapay/core";
2390
2426
  async function createPaymentIntentCore(request, body, options = {}) {
2391
2427
  try {
2392
2428
  if (!body.planRef || !body.productRef) {