@delopay/sdk 0.35.1 → 0.37.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/README.md CHANGED
@@ -273,6 +273,36 @@ const all = await delopay.subscriptions.list({ limit: 20 }, opts);
273
273
  Each billing cycle raises an invoice (`sub.invoice`) with its own payment leg
274
274
  (`sub.payment`); track cycle outcomes via the subscription/invoice webhooks.
275
275
 
276
+ ### Platform fee rules
277
+
278
+ Price the platform fee by payment method, connector, amount, currency or card
279
+ network. Build the rule program with `feeProgram()` — rules are tried in order,
280
+ first match wins, otherwise the default applies:
281
+
282
+ ```typescript
283
+ import { Delopay, feeProgram } from '@delopay/sdk';
284
+
285
+ const delopay = new Delopay(process.env.DELOPAY_API_KEY ?? '');
286
+
287
+ const algorithm = feeProgram()
288
+ .rule({ name: 'crypto', when: { paymentMethod: 'crypto' }, fee: { percentage: 1.0 } })
289
+ .rule({
290
+ name: 'card_on_cryptomus',
291
+ when: { paymentMethod: 'card', connector: 'cryptomus' },
292
+ fee: { percentage: 2.0 },
293
+ })
294
+ .otherwise({ percentage: 3.0 })
295
+ .build();
296
+
297
+ await delopay.fees.rules.upsert({ algorithm }, 'merchant_abc123');
298
+
299
+ const program = await delopay.fees.rules.retrieve('merchant_abc123'); // or null
300
+ await delopay.fees.rules.delete('merchant_abc123'); // revert to flat schedules
301
+ ```
302
+
303
+ Merchants without a rule program keep their existing flat fee schedules / volume
304
+ tier unchanged.
305
+
276
306
  ### Webhook verification
277
307
 
278
308
  Delopay signs each outgoing webhook with HMAC-SHA512 over the raw request body and delivers the hex-encoded digest in the `X-Webhook-Signature-512` header. Use `express.raw()` (not `express.json()`) so the bytes reach the verifier unchanged.
@@ -625,6 +625,7 @@ var Events = class {
625
625
  var Fees = class {
626
626
  constructor(request) {
627
627
  this.request = request;
628
+ this.rules = new FeeRulesManager(request);
628
629
  }
629
630
  /**
630
631
  * Create a merchant-scoped fee schedule (optionally per-shop).
@@ -666,6 +667,46 @@ var Fees = class {
666
667
  return this.request("DELETE", `/merchant-fees/${encodeURIComponent(feeId)}`);
667
668
  }
668
669
  };
670
+ var FeeRulesManager = class {
671
+ constructor(request) {
672
+ this.request = request;
673
+ }
674
+ /**
675
+ * Create or replace the merchant's fee-rule program (a new active version;
676
+ * the previous version is deactivated server-side).
677
+ *
678
+ * @param params - The program plus optional name / shop scope / validity window.
679
+ * @param merchantId - The merchant account ID.
680
+ */
681
+ async upsert(params, merchantId) {
682
+ const body = { ...params, fee_owner: "merchant" };
683
+ return this.request("PUT", "/merchant-fees/rules", {
684
+ body,
685
+ query: { merchant_id: merchantId }
686
+ });
687
+ }
688
+ /**
689
+ * Retrieve the merchant's active fee-rule program, or `null` if none.
690
+ *
691
+ * @param merchantId - The merchant account ID.
692
+ */
693
+ async retrieve(merchantId) {
694
+ return this.request("GET", "/merchant-fees/rules", {
695
+ query: { merchant_id: merchantId }
696
+ });
697
+ }
698
+ /**
699
+ * Deactivate the merchant's active fee-rule program (falls back to the flat
700
+ * fee schedules / volume tier). Idempotent.
701
+ *
702
+ * @param merchantId - The merchant account ID.
703
+ */
704
+ async delete(merchantId) {
705
+ await this.request("DELETE", "/merchant-fees/rules", {
706
+ query: { merchant_id: merchantId }
707
+ });
708
+ }
709
+ };
669
710
 
670
711
  // src/resources/mandates.ts
671
712
  var Mandates = class {
@@ -2314,51 +2355,23 @@ var Webhooks = {
2314
2355
  };
2315
2356
 
2316
2357
  // src/resources/analytics.ts
2317
- var AnalyticsDomain = class {
2318
- constructor(request, domain) {
2319
- this.request = request;
2320
- this.domain = domain;
2321
- }
2322
- /** Get metrics. `POST /analytics/metrics/{domain}` */
2323
- async metrics(params, scope) {
2324
- const prefix = scope ? `/analytics/${scope}` : "/analytics";
2325
- return this.request("POST", `${prefix}/metrics/${encodeURIComponent(this.domain)}`, {
2326
- body: [params]
2327
- });
2328
- }
2329
- /** Get filters. `POST /analytics/filters/{domain}` */
2330
- async filters(params, scope) {
2331
- const prefix = scope ? `/analytics/${scope}` : "/analytics";
2332
- return this.request("POST", `${prefix}/filters/${encodeURIComponent(this.domain)}`, {
2333
- body: params
2334
- });
2335
- }
2336
- /** Generate report. `POST /analytics/report/{domain}` */
2337
- async report(params, scope) {
2338
- const prefix = scope ? `/analytics/${scope}` : "/analytics";
2339
- return this.request("POST", `${prefix}/report/${encodeURIComponent(this.domain)}`, {
2340
- body: params
2341
- });
2342
- }
2343
- /** Sankey chart data. `POST /analytics/metrics/{domain}/sankey` */
2344
- async sankey(params, scope) {
2345
- const prefix = scope ? `/analytics/${scope}` : "/analytics";
2346
- return this.request("POST", `${prefix}/metrics/${encodeURIComponent(this.domain)}/sankey`, {
2347
- body: params
2348
- });
2349
- }
2350
- };
2351
2358
  var Analytics = class {
2352
2359
  constructor(request) {
2353
2360
  this.request = request;
2354
- this.payments = new AnalyticsDomain(request, "payments");
2355
- this.refunds = new AnalyticsDomain(request, "refunds");
2356
- this.disputes = new AnalyticsDomain(request, "disputes");
2357
- this.authEvents = new AnalyticsDomain(request, "auth_events");
2358
- this.sdkEvents = new AnalyticsDomain(request, "sdk_events");
2359
- this.frm = new AnalyticsDomain(request, "frm");
2360
- this.apiEvents = new AnalyticsDomain(request, "api_events");
2361
- this.routing = new AnalyticsDomain(request, "routing");
2361
+ }
2362
+ /**
2363
+ * Scoped, drill-level analytics dashboard for the authenticated merchant
2364
+ * (the same engine as the admin portal, pinned server-side to your own
2365
+ * merchant). The server ignores `merchant_id` — it always scopes to your
2366
+ * merchant, and to your single shop for profile-scoped users — so pass only
2367
+ * `project_id` / `shop_id` to drill and the window / `sections` fields.
2368
+ * Returns one drill level: the scope's daily series + previous window,
2369
+ * processor mix and direct children. `GET /analytics/scope`
2370
+ */
2371
+ async scope(params) {
2372
+ return this.request("GET", "/analytics/scope", {
2373
+ query: params
2374
+ });
2362
2375
  }
2363
2376
  /** Global search. `POST /analytics/search` */
2364
2377
  async search(params) {
@@ -3017,6 +3030,74 @@ var Delopay = class {
3017
3030
  /** Utility for verifying incoming webhook signatures (static, no instance needed). */
3018
3031
  Delopay.webhooks = Webhooks;
3019
3032
 
3033
+ // src/feeProgram.ts
3034
+ function toFeeOutput(spec) {
3035
+ const hasPct = spec.percentage != null;
3036
+ const hasFlat = spec.flat != null;
3037
+ const feeType = hasPct && hasFlat ? "combined" : hasFlat ? "flat" : "percentage";
3038
+ return {
3039
+ fee_type: feeType,
3040
+ percentage_fee: spec.percentage ?? null,
3041
+ flat_fee_amount: spec.flat ?? null,
3042
+ flat_fee_currency: spec.flatCurrency ?? null,
3043
+ min_fee_amount: spec.min ?? null,
3044
+ max_fee_amount: spec.max ?? null
3045
+ };
3046
+ }
3047
+ function enumCondition(lhs, value) {
3048
+ return { lhs, comparison: "equal", value: { type: "enum_variant", value }, metadata: {} };
3049
+ }
3050
+ function numberCondition(lhs, comparison, value) {
3051
+ return { lhs, comparison, value: { type: "number", value }, metadata: {} };
3052
+ }
3053
+ function buildConditions(when = {}, raw = []) {
3054
+ const out = [];
3055
+ if (when.paymentMethod != null) out.push(enumCondition("payment_method", when.paymentMethod));
3056
+ if (when.connector != null) out.push(enumCondition("connector", when.connector));
3057
+ if (when.currency != null) out.push(enumCondition("currency", when.currency));
3058
+ if (when.cardNetwork != null) out.push(enumCondition("card_network", when.cardNetwork));
3059
+ if (when.amountEquals != null) out.push(numberCondition("amount", "equal", when.amountEquals));
3060
+ if (when.amountGreaterThan != null) {
3061
+ out.push(numberCondition("amount", "greater_than", when.amountGreaterThan));
3062
+ }
3063
+ if (when.amountLessThan != null) {
3064
+ out.push(numberCondition("amount", "less_than", when.amountLessThan));
3065
+ }
3066
+ out.push(...raw);
3067
+ return out;
3068
+ }
3069
+ var FeeProgramBuilder = class {
3070
+ constructor() {
3071
+ this.rules = [];
3072
+ this.defaultFee = null;
3073
+ }
3074
+ /** Append a rule. Provided `when`/`rawConditions` are ANDed. */
3075
+ rule(input) {
3076
+ this.rules.push({
3077
+ name: input.name,
3078
+ connectorSelection: { fee: toFeeOutput(input.fee) },
3079
+ statements: [{ condition: buildConditions(input.when, input.rawConditions) }]
3080
+ });
3081
+ return this;
3082
+ }
3083
+ /** Set the default selection (applied when no rule matches). */
3084
+ otherwise(fee) {
3085
+ this.defaultFee = toFeeOutput(fee);
3086
+ return this;
3087
+ }
3088
+ /** Produce the wire-ready program. */
3089
+ build() {
3090
+ return {
3091
+ defaultSelection: { fee: this.defaultFee },
3092
+ rules: this.rules,
3093
+ metadata: {}
3094
+ };
3095
+ }
3096
+ };
3097
+ function feeProgram() {
3098
+ return new FeeProgramBuilder();
3099
+ }
3100
+
3020
3101
  // src/branding.ts
3021
3102
  var FONT_STACKS = {
3022
3103
  inter: "'Inter Variable', 'Inter', system-ui, -apple-system, sans-serif",
@@ -3663,6 +3744,8 @@ export {
3663
3744
  Regions,
3664
3745
  Subscriptions,
3665
3746
  Delopay,
3747
+ FeeProgramBuilder,
3748
+ feeProgram,
3666
3749
  fontStack,
3667
3750
  radiusValue,
3668
3751
  fontWeightValue,
@@ -3692,4 +3775,4 @@ export {
3692
3775
  applyBrandingVariables,
3693
3776
  shadowFor
3694
3777
  };
3695
- //# sourceMappingURL=chunk-45OPT3EW.js.map
3778
+ //# sourceMappingURL=chunk-IQKFNKHU.js.map