@garuhq/node 0.6.0 → 0.7.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.cjs CHANGED
@@ -464,11 +464,80 @@ var Meta = class {
464
464
  };
465
465
 
466
466
  // src/resources/products.ts
467
+ var ProductPortalConfigResource = class {
468
+ constructor(http) {
469
+ this.http = http;
470
+ }
471
+ http;
472
+ /**
473
+ * Get the portal customization for a product. Returns `null` when no
474
+ * per-product config exists (the product falls back to seller-level
475
+ * portal config).
476
+ *
477
+ * @example
478
+ * const cfg = await garu.products.portalConfig.get(57);
479
+ */
480
+ async get(productId) {
481
+ return this.http.call(
482
+ (signal) => this.http.client.GET(`/api/products/${productId}/portal-config`, {
483
+ signal
484
+ }).then((r) => r)
485
+ );
486
+ }
487
+ /**
488
+ * Create or merge the portal customization (idempotent upsert). Both
489
+ * `set` and `patch` have the same merge semantics — only fields present
490
+ * in the body are written, unspecified fields keep their persisted
491
+ * value. Use `clear` to reset everything.
492
+ *
493
+ * @example
494
+ * await garu.products.portalConfig.set(57, {
495
+ * businessName: 'Coach Maria — Corrida & Trilha',
496
+ * primaryColor: '#257264',
497
+ * logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
498
+ * });
499
+ */
500
+ async set(productId, params) {
501
+ return this.http.call(
502
+ (signal) => this.http.client.POST(`/api/products/${productId}/portal-config`, {
503
+ body: params,
504
+ signal
505
+ }).then((r) => r)
506
+ );
507
+ }
508
+ /** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
509
+ async patch(productId, params) {
510
+ return this.http.call(
511
+ (signal) => this.http.client.PATCH(`/api/products/${productId}/portal-config`, {
512
+ body: params,
513
+ signal
514
+ }).then((r) => r)
515
+ );
516
+ }
517
+ /**
518
+ * Remove the per-product config. The product falls back to the
519
+ * seller-level portal config. Returns `{ removed: true }` when a row was
520
+ * deleted, `{ removed: false }` when there was nothing to remove.
521
+ *
522
+ * @example
523
+ * await garu.products.portalConfig.clear(57);
524
+ */
525
+ async clear(productId) {
526
+ return this.http.call(
527
+ (signal) => this.http.client.DELETE(`/api/products/${productId}/portal-config`, {
528
+ signal
529
+ }).then((r) => r)
530
+ );
531
+ }
532
+ };
467
533
  var Products = class {
468
534
  constructor(http) {
469
535
  this.http = http;
536
+ this.portalConfig = new ProductPortalConfigResource(http);
470
537
  }
471
538
  http;
539
+ /** Per-product portal customization (Garu v0.8.0). */
540
+ portalConfig;
472
541
  /**
473
542
  * List products for the authenticated seller, with pagination and search.
474
543
  *
package/dist/index.d.cts CHANGED
@@ -485,6 +485,98 @@ interface MetaResponse {
485
485
  dashboard_url: string;
486
486
  support_email: string;
487
487
  }
488
+ /**
489
+ * Canonical Garu failure code on `transaction.payment.failed` and
490
+ * `scheduled_charge.cycle_failed` events. Stable across acquirer changes —
491
+ * branch on this rather than the raw Celcoin code.
492
+ */
493
+ type GaruFailureCode = 'insufficient_funds' | 'card_declined' | 'card_expired' | 'card_canceled' | 'processing_error' | 'issuer_unavailable' | 'fraud_suspected' | 'invalid_cvv' | 'do_not_honor_repeated' | 'unknown';
494
+ /**
495
+ * Shape of the failure trio added to `transaction.payment.failed` and
496
+ * `scheduled_charge.cycle_failed` payloads. Sellers should always receive
497
+ * a non-null `failureCode` — `unknown` is the sentinel when the gateway
498
+ * didn't surface enough detail to map.
499
+ */
500
+ interface FailurePayload {
501
+ failureCode: GaruFailureCode;
502
+ failureReason: string | null;
503
+ /** Raw acquirer code (Celcoin's ABECS code today). For forensics only. */
504
+ gatewayFailureCode: string | null;
505
+ }
506
+ /**
507
+ * `payment_method.expiring_soon` — fires at 30/14/7 days before card
508
+ * expiry, idempotent per stage. Use to nudge the customer to update
509
+ * their card before silent-charge starts failing.
510
+ */
511
+ interface PaymentMethodExpiringPayload {
512
+ paymentMethodId: number;
513
+ customerId: number;
514
+ cardLast4: string;
515
+ cardBrand: string;
516
+ expiresAt: string;
517
+ daysUntilExpiry: 30 | 14 | 7;
518
+ }
519
+ /**
520
+ * `payment_method.expired` — fires once on the day-of-expiry when the cron
521
+ * flips `status='expired'`. Future silent charges short-circuit
522
+ * with `failureCode='card_expired'` instead of hitting the acquirer.
523
+ */
524
+ interface PaymentMethodExpiredPayload {
525
+ paymentMethodId: number;
526
+ customerId: number;
527
+ cardLast4: string;
528
+ cardBrand: string;
529
+ expiresAt: string;
530
+ }
531
+ /**
532
+ * Per-product portal customization (Atletia coach-as-product modeling and
533
+ * any other B2B2C platform). `null` fields inherit from the seller-level
534
+ * portal config.
535
+ */
536
+ interface ProductPortalConfig {
537
+ id: number;
538
+ productId: number;
539
+ businessName: string | null;
540
+ logoUrl: string | null;
541
+ primaryColor: string | null;
542
+ allowCancelSubscription: boolean | null;
543
+ allowUpdatePaymentMethod: boolean | null;
544
+ allowUpdateBillingInfo: boolean | null;
545
+ allowViewInvoices: boolean | null;
546
+ allowApplyCoupons: boolean | null;
547
+ requireCancelReason: boolean | null;
548
+ cancelAtPeriodEndOnly: boolean | null;
549
+ sendCancellationEmail: boolean | null;
550
+ sendPaymentMethodUpdatedEmail: boolean | null;
551
+ customSuccessMessage: string | null;
552
+ customCancellationMessage: string | null;
553
+ customWelcomeText: string | null;
554
+ createdAt: string;
555
+ updatedAt: string;
556
+ }
557
+ /**
558
+ * Body for `POST` / `PATCH /api/products/:id/portal-config`. Both verbs
559
+ * are upsert with merge semantics — only fields present are written;
560
+ * unspecified fields keep their persisted value. Use the `clear`
561
+ * method (DELETE) to reset everything.
562
+ */
563
+ interface SetProductPortalConfigParams {
564
+ businessName?: string | null;
565
+ logoUrl?: string | null;
566
+ primaryColor?: string | null;
567
+ allowCancelSubscription?: boolean | null;
568
+ allowUpdatePaymentMethod?: boolean | null;
569
+ allowUpdateBillingInfo?: boolean | null;
570
+ allowViewInvoices?: boolean | null;
571
+ allowApplyCoupons?: boolean | null;
572
+ requireCancelReason?: boolean | null;
573
+ cancelAtPeriodEndOnly?: boolean | null;
574
+ sendCancellationEmail?: boolean | null;
575
+ sendPaymentMethodUpdatedEmail?: boolean | null;
576
+ customSuccessMessage?: string | null;
577
+ customCancellationMessage?: string | null;
578
+ customWelcomeText?: string | null;
579
+ }
488
580
 
489
581
  /**
490
582
  * Charges — the core of the Garu API.
@@ -657,13 +749,61 @@ declare class Meta {
657
749
  }
658
750
 
659
751
  /**
660
- * Products discover products available to charge.
752
+ * Per-product portal customization (Garu v0.8.0). Used by B2B2C platforms
753
+ * that model their professionals/coaches as Products under a single seller
754
+ * and want per-product branding on the customer payment + portal pages.
755
+ */
756
+ declare class ProductPortalConfigResource {
757
+ private readonly http;
758
+ constructor(http: HttpClient);
759
+ /**
760
+ * Get the portal customization for a product. Returns `null` when no
761
+ * per-product config exists (the product falls back to seller-level
762
+ * portal config).
763
+ *
764
+ * @example
765
+ * const cfg = await garu.products.portalConfig.get(57);
766
+ */
767
+ get(productId: number): Promise<ProductPortalConfig | null>;
768
+ /**
769
+ * Create or merge the portal customization (idempotent upsert). Both
770
+ * `set` and `patch` have the same merge semantics — only fields present
771
+ * in the body are written, unspecified fields keep their persisted
772
+ * value. Use `clear` to reset everything.
773
+ *
774
+ * @example
775
+ * await garu.products.portalConfig.set(57, {
776
+ * businessName: 'Coach Maria — Corrida & Trilha',
777
+ * primaryColor: '#257264',
778
+ * logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
779
+ * });
780
+ */
781
+ set(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
782
+ /** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
783
+ patch(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
784
+ /**
785
+ * Remove the per-product config. The product falls back to the
786
+ * seller-level portal config. Returns `{ removed: true }` when a row was
787
+ * deleted, `{ removed: false }` when there was nothing to remove.
788
+ *
789
+ * @example
790
+ * await garu.products.portalConfig.clear(57);
791
+ */
792
+ clear(productId: number): Promise<{
793
+ removed: boolean;
794
+ }>;
795
+ }
796
+ /**
797
+ * Products — discover products available to charge, and customize the
798
+ * per-product portal experience (v0.8.0).
661
799
  *
662
800
  * Products are scoped to the seller identified by the API key. The UUID
663
801
  * returned here is the same identifier accepted by `charges.create({ productId })`.
664
802
  */
665
803
  declare class Products {
666
804
  private readonly http;
805
+ /** Per-product portal customization (Garu v0.8.0). */
806
+ readonly portalConfig: ProductPortalConfigResource;
667
807
  constructor(http: HttpClient);
668
808
  /**
669
809
  * List products for the authenticated seller, with pagination and search.
@@ -931,4 +1071,4 @@ declare class GaruServerError extends GaruAPIError {
931
1071
  constructor(message: string, status: number, requestId: string | null, body: unknown);
932
1072
  }
933
1073
 
934
- export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type CreateScheduledChargeParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type ListScheduledChargesParams, type MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PostponeScheduledChargeParams, type Product, type ProductList, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type ScheduledChargeDetail, type ScheduledChargeEvent, type ScheduledChargeEventType, type ScheduledChargeLinkedTransaction, type ScheduledChargeList, type ScheduledChargeRecord, type ScheduledChargeStatus, type ScheduledChargeType, type ScheduledPaymentMethod, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
1074
+ export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type CreateScheduledChargeParams, type Customer, type CustomerList, type CustomerRecord, type FailurePayload, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, type GaruFailureCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type ListScheduledChargesParams, type MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PaymentMethodExpiredPayload, type PaymentMethodExpiringPayload, type PostponeScheduledChargeParams, type Product, type ProductList, type ProductPortalConfig, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type ScheduledChargeDetail, type ScheduledChargeEvent, type ScheduledChargeEventType, type ScheduledChargeLinkedTransaction, type ScheduledChargeList, type ScheduledChargeRecord, type ScheduledChargeStatus, type ScheduledChargeType, type ScheduledPaymentMethod, type SetProductPortalConfigParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
package/dist/index.d.ts CHANGED
@@ -485,6 +485,98 @@ interface MetaResponse {
485
485
  dashboard_url: string;
486
486
  support_email: string;
487
487
  }
488
+ /**
489
+ * Canonical Garu failure code on `transaction.payment.failed` and
490
+ * `scheduled_charge.cycle_failed` events. Stable across acquirer changes —
491
+ * branch on this rather than the raw Celcoin code.
492
+ */
493
+ type GaruFailureCode = 'insufficient_funds' | 'card_declined' | 'card_expired' | 'card_canceled' | 'processing_error' | 'issuer_unavailable' | 'fraud_suspected' | 'invalid_cvv' | 'do_not_honor_repeated' | 'unknown';
494
+ /**
495
+ * Shape of the failure trio added to `transaction.payment.failed` and
496
+ * `scheduled_charge.cycle_failed` payloads. Sellers should always receive
497
+ * a non-null `failureCode` — `unknown` is the sentinel when the gateway
498
+ * didn't surface enough detail to map.
499
+ */
500
+ interface FailurePayload {
501
+ failureCode: GaruFailureCode;
502
+ failureReason: string | null;
503
+ /** Raw acquirer code (Celcoin's ABECS code today). For forensics only. */
504
+ gatewayFailureCode: string | null;
505
+ }
506
+ /**
507
+ * `payment_method.expiring_soon` — fires at 30/14/7 days before card
508
+ * expiry, idempotent per stage. Use to nudge the customer to update
509
+ * their card before silent-charge starts failing.
510
+ */
511
+ interface PaymentMethodExpiringPayload {
512
+ paymentMethodId: number;
513
+ customerId: number;
514
+ cardLast4: string;
515
+ cardBrand: string;
516
+ expiresAt: string;
517
+ daysUntilExpiry: 30 | 14 | 7;
518
+ }
519
+ /**
520
+ * `payment_method.expired` — fires once on the day-of-expiry when the cron
521
+ * flips `status='expired'`. Future silent charges short-circuit
522
+ * with `failureCode='card_expired'` instead of hitting the acquirer.
523
+ */
524
+ interface PaymentMethodExpiredPayload {
525
+ paymentMethodId: number;
526
+ customerId: number;
527
+ cardLast4: string;
528
+ cardBrand: string;
529
+ expiresAt: string;
530
+ }
531
+ /**
532
+ * Per-product portal customization (Atletia coach-as-product modeling and
533
+ * any other B2B2C platform). `null` fields inherit from the seller-level
534
+ * portal config.
535
+ */
536
+ interface ProductPortalConfig {
537
+ id: number;
538
+ productId: number;
539
+ businessName: string | null;
540
+ logoUrl: string | null;
541
+ primaryColor: string | null;
542
+ allowCancelSubscription: boolean | null;
543
+ allowUpdatePaymentMethod: boolean | null;
544
+ allowUpdateBillingInfo: boolean | null;
545
+ allowViewInvoices: boolean | null;
546
+ allowApplyCoupons: boolean | null;
547
+ requireCancelReason: boolean | null;
548
+ cancelAtPeriodEndOnly: boolean | null;
549
+ sendCancellationEmail: boolean | null;
550
+ sendPaymentMethodUpdatedEmail: boolean | null;
551
+ customSuccessMessage: string | null;
552
+ customCancellationMessage: string | null;
553
+ customWelcomeText: string | null;
554
+ createdAt: string;
555
+ updatedAt: string;
556
+ }
557
+ /**
558
+ * Body for `POST` / `PATCH /api/products/:id/portal-config`. Both verbs
559
+ * are upsert with merge semantics — only fields present are written;
560
+ * unspecified fields keep their persisted value. Use the `clear`
561
+ * method (DELETE) to reset everything.
562
+ */
563
+ interface SetProductPortalConfigParams {
564
+ businessName?: string | null;
565
+ logoUrl?: string | null;
566
+ primaryColor?: string | null;
567
+ allowCancelSubscription?: boolean | null;
568
+ allowUpdatePaymentMethod?: boolean | null;
569
+ allowUpdateBillingInfo?: boolean | null;
570
+ allowViewInvoices?: boolean | null;
571
+ allowApplyCoupons?: boolean | null;
572
+ requireCancelReason?: boolean | null;
573
+ cancelAtPeriodEndOnly?: boolean | null;
574
+ sendCancellationEmail?: boolean | null;
575
+ sendPaymentMethodUpdatedEmail?: boolean | null;
576
+ customSuccessMessage?: string | null;
577
+ customCancellationMessage?: string | null;
578
+ customWelcomeText?: string | null;
579
+ }
488
580
 
489
581
  /**
490
582
  * Charges — the core of the Garu API.
@@ -657,13 +749,61 @@ declare class Meta {
657
749
  }
658
750
 
659
751
  /**
660
- * Products discover products available to charge.
752
+ * Per-product portal customization (Garu v0.8.0). Used by B2B2C platforms
753
+ * that model their professionals/coaches as Products under a single seller
754
+ * and want per-product branding on the customer payment + portal pages.
755
+ */
756
+ declare class ProductPortalConfigResource {
757
+ private readonly http;
758
+ constructor(http: HttpClient);
759
+ /**
760
+ * Get the portal customization for a product. Returns `null` when no
761
+ * per-product config exists (the product falls back to seller-level
762
+ * portal config).
763
+ *
764
+ * @example
765
+ * const cfg = await garu.products.portalConfig.get(57);
766
+ */
767
+ get(productId: number): Promise<ProductPortalConfig | null>;
768
+ /**
769
+ * Create or merge the portal customization (idempotent upsert). Both
770
+ * `set` and `patch` have the same merge semantics — only fields present
771
+ * in the body are written, unspecified fields keep their persisted
772
+ * value. Use `clear` to reset everything.
773
+ *
774
+ * @example
775
+ * await garu.products.portalConfig.set(57, {
776
+ * businessName: 'Coach Maria — Corrida & Trilha',
777
+ * primaryColor: '#257264',
778
+ * logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
779
+ * });
780
+ */
781
+ set(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
782
+ /** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
783
+ patch(productId: number, params: SetProductPortalConfigParams): Promise<ProductPortalConfig>;
784
+ /**
785
+ * Remove the per-product config. The product falls back to the
786
+ * seller-level portal config. Returns `{ removed: true }` when a row was
787
+ * deleted, `{ removed: false }` when there was nothing to remove.
788
+ *
789
+ * @example
790
+ * await garu.products.portalConfig.clear(57);
791
+ */
792
+ clear(productId: number): Promise<{
793
+ removed: boolean;
794
+ }>;
795
+ }
796
+ /**
797
+ * Products — discover products available to charge, and customize the
798
+ * per-product portal experience (v0.8.0).
661
799
  *
662
800
  * Products are scoped to the seller identified by the API key. The UUID
663
801
  * returned here is the same identifier accepted by `charges.create({ productId })`.
664
802
  */
665
803
  declare class Products {
666
804
  private readonly http;
805
+ /** Per-product portal customization (Garu v0.8.0). */
806
+ readonly portalConfig: ProductPortalConfigResource;
667
807
  constructor(http: HttpClient);
668
808
  /**
669
809
  * List products for the authenticated seller, with pagination and search.
@@ -931,4 +1071,4 @@ declare class GaruServerError extends GaruAPIError {
931
1071
  constructor(message: string, status: number, requestId: string | null, body: unknown);
932
1072
  }
933
1073
 
934
- export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type CreateScheduledChargeParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type ListScheduledChargesParams, type MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PostponeScheduledChargeParams, type Product, type ProductList, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type ScheduledChargeDetail, type ScheduledChargeEvent, type ScheduledChargeEventType, type ScheduledChargeLinkedTransaction, type ScheduledChargeList, type ScheduledChargeRecord, type ScheduledChargeStatus, type ScheduledChargeType, type ScheduledPaymentMethod, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
1074
+ export { type CancelAtPeriodEndScheduledChargeParams, type CancelRecurrenceScheduledChargeParams, type CardInfo, type ChangePaymentMethodScheduledChargeParams, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type CreateScheduledChargeParams, type Customer, type CustomerList, type CustomerRecord, type FailurePayload, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, type GaruFailureCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type ListScheduledChargesParams, type MarkPaidScheduledChargeParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PauseScheduledChargeParams, type PaymentMethod, type PaymentMethodExpiredPayload, type PaymentMethodExpiringPayload, type PostponeScheduledChargeParams, type Product, type ProductList, type ProductPortalConfig, type RecurrenceConfig, type RecurrenceInterval, type RefundChargeParams, type ScheduledChargeActor, type ScheduledChargeDetail, type ScheduledChargeEvent, type ScheduledChargeEventType, type ScheduledChargeLinkedTransaction, type ScheduledChargeList, type ScheduledChargeRecord, type ScheduledChargeStatus, type ScheduledChargeType, type ScheduledPaymentMethod, type SetProductPortalConfigParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
package/dist/index.js CHANGED
@@ -458,11 +458,80 @@ var Meta = class {
458
458
  };
459
459
 
460
460
  // src/resources/products.ts
461
+ var ProductPortalConfigResource = class {
462
+ constructor(http) {
463
+ this.http = http;
464
+ }
465
+ http;
466
+ /**
467
+ * Get the portal customization for a product. Returns `null` when no
468
+ * per-product config exists (the product falls back to seller-level
469
+ * portal config).
470
+ *
471
+ * @example
472
+ * const cfg = await garu.products.portalConfig.get(57);
473
+ */
474
+ async get(productId) {
475
+ return this.http.call(
476
+ (signal) => this.http.client.GET(`/api/products/${productId}/portal-config`, {
477
+ signal
478
+ }).then((r) => r)
479
+ );
480
+ }
481
+ /**
482
+ * Create or merge the portal customization (idempotent upsert). Both
483
+ * `set` and `patch` have the same merge semantics — only fields present
484
+ * in the body are written, unspecified fields keep their persisted
485
+ * value. Use `clear` to reset everything.
486
+ *
487
+ * @example
488
+ * await garu.products.portalConfig.set(57, {
489
+ * businessName: 'Coach Maria — Corrida & Trilha',
490
+ * primaryColor: '#257264',
491
+ * logoUrl: 'https://cdn.atletia.com.br/coaches/maria.png'
492
+ * });
493
+ */
494
+ async set(productId, params) {
495
+ return this.http.call(
496
+ (signal) => this.http.client.POST(`/api/products/${productId}/portal-config`, {
497
+ body: params,
498
+ signal
499
+ }).then((r) => r)
500
+ );
501
+ }
502
+ /** Same merge semantics as `set` — alias for HTTP-PATCH-prefering callers. */
503
+ async patch(productId, params) {
504
+ return this.http.call(
505
+ (signal) => this.http.client.PATCH(`/api/products/${productId}/portal-config`, {
506
+ body: params,
507
+ signal
508
+ }).then((r) => r)
509
+ );
510
+ }
511
+ /**
512
+ * Remove the per-product config. The product falls back to the
513
+ * seller-level portal config. Returns `{ removed: true }` when a row was
514
+ * deleted, `{ removed: false }` when there was nothing to remove.
515
+ *
516
+ * @example
517
+ * await garu.products.portalConfig.clear(57);
518
+ */
519
+ async clear(productId) {
520
+ return this.http.call(
521
+ (signal) => this.http.client.DELETE(`/api/products/${productId}/portal-config`, {
522
+ signal
523
+ }).then((r) => r)
524
+ );
525
+ }
526
+ };
461
527
  var Products = class {
462
528
  constructor(http) {
463
529
  this.http = http;
530
+ this.portalConfig = new ProductPortalConfigResource(http);
464
531
  }
465
532
  http;
533
+ /** Per-product portal customization (Garu v0.8.0). */
534
+ portalConfig;
466
535
  /**
467
536
  * List products for the authenticated seller, with pagination and search.
468
537
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/node",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Official Node.js / TypeScript SDK for the Garu payment gateway.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://garu.com.br",