@skalpgg/sdk 1.3.0 → 1.4.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
@@ -65,13 +65,12 @@ Create the key on the API keys page of your dashboard. Each key is bound to one
65
65
  | `coupons.create({ code, discountType?, discountPercent?, discountAmount?, validFrom?, validTo?, maxUses?, ... })` / `coupons.update(id, { ... })` / `coupons.delete(id)` | `coupons:write` |
66
66
  | `customers.list({ search?, limit?, offset? })` / `customers.get(id)` | `customers:read` |
67
67
  | `customers.create({ email, name?, note? })` / `customers.update(id, { name?, note? })` / `customers.delete(id)` | `customers:write` |
68
- | `customers.adjustBalance(id, { amount, reason? })` | `customers:write` |
69
68
  | `feedback.list({ productId?, rating?, limit?, offset? })` / `feedback.get(id)` | `feedback:read` |
70
69
  | `feedback.reply(id, { message })` / `feedback.appeal(id, { reason })` | `feedback:write` |
71
70
  | `queries.list({ status?, limit?, offset? })` / `queries.get(id)` | `queries:read` |
72
71
  | `queries.reply(id, { message })` / `queries.close(id)` / `queries.reopen(id)` | `queries:write` |
73
- | `blacklist.list({ type? })` / `whitelist.list({ type? })` | `blacklist:read` |
74
- | `blacklist.add({ type, value, note? })` / `whitelist.add({ ... })` / `blacklist.remove(id)` / `whitelist.remove(id)` | `blacklist:write` |
72
+ | `blacklist.list({ type? })` / `blacklist.add({ type, value, note? })` / `blacklist.remove(id)` | `blacklist:read` / `blacklist:write` |
73
+ | `whitelist.list({ type? })` / `whitelist.add({ type, value, note? })` / `whitelist.remove(id)` | `whitelist:read` / `whitelist:write` |
75
74
  | `subscriptions.createCheckout({ productId \| productSlug, externalRef?, customerEmail?, currency?, ... })` | `checkout:write` |
76
75
  | `subscriptions.getCheckout(id)` | `checkout:read` |
77
76
  | `subscriptions.list({ externalRef?, status?, updatedSince?, limit?, offset? })` | `subscriptions:read` |
@@ -119,19 +118,17 @@ const { data: orders } = await skalp.orders.list({ status: 'COMPLETED', updatedS
119
118
  await skalp.orders.cancel(order.id)
120
119
 
121
120
  const { replacements } = await skalp.orders.replace(order.id, { reason: 'Key does not activate' })
122
-
123
- await skalp.customers.adjustBalance(customer.id, { amount: 10, reason: 'Goodwill credit' })
124
121
  ```
125
122
 
126
- `cancel` works only on a `PENDING` order and returns it as `CANCELED`. `replace` swaps the delivered keys of a completed order: with no `serialIds` it replaces every key, and with no `values` it draws the new ones from stock (`values` is required for keys that come from your server). The replacement keys come back in `replacements[].value`. `orders.get` also returns `serialsReplaced` and the `replacements` history.
123
+ `cancel` works only on a `PENDING` order and returns it as `CANCELED`. `replace` swaps the delivered keys of a completed order: with no `serialIds` it replaces every key, and with no `values` it draws the new ones from stock (`values` is required for keys that come from your server). The replacement keys come back in `replacements[].value`. `orders.get` also returns `serialsReplaced`, the `replacements` history and `serials`: the id, status, `deliveredAt` and `replacedById` of every delivered or replaced key (never its value), which are the ids `serialIds` expects.
127
124
 
128
- `updatedSince` lists oldest change first, so you can page through it and keep the last `updatedAt` as your cursor; without it, newest orders come first. Amounts are in major units (`19.5`), balances cannot go below zero, and a customer with a balance cannot be deleted.
125
+ `updatedSince` lists oldest change first, so you can page through it and keep the last `updatedAt` as your cursor; without it, newest orders come first. Amounts are in major units (`19.5`).
129
126
 
130
127
  Coupons take `validFrom`, `validTo` as an ISO string or a `Date`; `coupons.update` accepts `null` to clear `validTo`, `maxUses`, `minPurchaseAmount` and `description`.
131
128
 
132
129
  ## Support and access rules
133
130
 
134
- `feedback` and `queries` expose product reviews and buyer conversations. `queries.reply`, `close` and `reopen` return the whole conversation with its `messages`. `blacklist` and `whitelist` use the same calls and the same `blacklist:read` and `blacklist:write` scopes; a whitelisted buyer is never blocked by a blacklist rule.
131
+ `feedback` and `queries` expose product reviews and buyer conversations. `queries.reply`, `close` and `reopen` return the whole conversation with its `messages`. `blacklist` and `whitelist` use the same calls, each with its own read and write scope; a whitelisted buyer is never blocked by a blacklist rule.
135
132
 
136
133
  ```ts
137
134
  await skalp.blacklist.add({ type: 'EMAIL', value: 'chargeback@example.com', note: 'Disputed order 1042' })
@@ -174,7 +171,7 @@ export async function POST(request: Request) {
174
171
 
175
172
  A webhook with the default events receives every purchase as both `order.paid` and its legacy name `purchase.completed`. Handle `order.paid` and deduplicate on `data.idempotencyKey`.
176
173
 
177
- `order.created`, `order.updated`, `order.canceled`, `order.replaced`, `query.created`, `query.replied`, `feedback.received` and the subscription events `subscription.updated`, `subscription.trial_started`, `subscription.trial_ended` and `subscription.upcoming` are not in the default list either: subscribe the webhook to them by name, and `event.type` narrows `event.data` to the right payload. `order.created`, `order.updated` and `order.canceled` carry the order as `orders.get` returns it, plus `previousStatus`; `order.replaced` adds `reason` and the new keys in `replacements[].key`. The three trial and upcoming events are accepted by the API but the backend does not send them yet.
174
+ `order.created`, `order.updated`, `order.canceled`, `order.replaced`, `query.created`, `query.replied`, `feedback.received` and the subscription events `subscription.updated`, `subscription.trial_started`, `subscription.trial_ended` and `subscription.upcoming` are not in the default list either: subscribe the webhook to them by name, and `event.type` narrows `event.data` to the right payload. `order.created`, `order.updated` and `order.canceled` carry the order as `orders.get` returns it, plus `previousStatus`; `order.replaced` adds `reason` and the new keys in `replacements[].key`. Every one of them, like `query.created`, `query.replied` and `feedback.received`, carries a `data.idempotencyKey` that stays the same on every retry of the same event, so deduplicate on it. The three trial and upcoming events are accepted by the API but the backend does not send them yet.
178
175
 
179
176
  `product.created`, `product.updated` and `product.stock` are not in the default list: subscribe the webhook to them by name. `product.stock` carries `stock`, `previousStock` and `change` whenever the number of available keys changes.
180
177
 
@@ -1,6 +1,6 @@
1
- import type { AccessRule, AddAccessRuleParams, AddSerialsParams, AddSerialsResult, AdjustCustomerBalanceParams, AppealFeedbackParams, ChangeSubscriptionPlanParams, CheckoutSession, CheckoutSessionStatus, CoinCheckout, CoinCheckoutStatus, Coupon, CreateCheckoutParams, CreateCoinCheckoutParams, CreateCouponParams, CreateCustomerParams, CreateProductGroupParams, CreateProductParams, CreateStoreCategoryParams, CreateSubscriptionCheckoutParams, CreateUsageChargeParams, Customer, CustomerDetails, CustomerList, Deleted, Feedback, FeedbackList, HeartbeatParams, Invoice, LicenseKeyInfo, LicenseValidation, LicenseVerification, ListAccessRulesParams, ListCustomersParams, ListFeedbackParams, ListOrdersParams, ListProductsParams, ListQueriesParams, ListSerialsParams, ListSubscriptionsParams, Order, OrderKeysReplaced, OrderList, Product, ProductGroup, ProductStock, ReplaceOrderKeysParams, ReplyParams, SerialList, SkalpEvent, StoreCategory, StoreCategoryWithCount, Subscription, SubscriptionCheckout, SubscriptionCheckoutStatus, SubscriptionList, SupportQueryDetails, SupportQueryList, ResetLicenseDevicesParams, UpdateCouponParams, UpdateCustomerParams, UpdateProductGroupParams, UpdateProductParams, UpdateStoreCategoryParams, UsageCharge, ValidateLicenseParams, VerifyLicenseParams } from './types.js';
1
+ import type { AccessRule, AddAccessRuleParams, AddSerialsParams, AddSerialsResult, AppealFeedbackParams, ChangeSubscriptionPlanParams, CheckoutSession, CheckoutSessionStatus, CoinCheckout, CoinCheckoutStatus, Coupon, CreateCheckoutParams, CreateCoinCheckoutParams, CreateCouponParams, CreateCustomerParams, CreateProductGroupParams, CreateProductParams, CreateStoreCategoryParams, CreateSubscriptionCheckoutParams, CreateUsageChargeParams, Customer, CustomerDetails, CustomerList, Deleted, Feedback, FeedbackList, HeartbeatParams, Invoice, LicenseKeyInfo, LicenseValidation, LicenseVerification, ListAccessRulesParams, ListCustomersParams, ListFeedbackParams, ListOrdersParams, ListProductsParams, ListQueriesParams, ListSerialsParams, ListSubscriptionsParams, Order, OrderKeysReplaced, OrderList, Product, ProductGroup, ProductStock, ReplaceOrderKeysParams, ReplyParams, SerialList, SkalpEvent, StoreCategory, StoreCategoryWithCount, Subscription, SubscriptionCheckout, SubscriptionCheckoutStatus, SubscriptionList, SupportQueryDetails, SupportQueryList, ResetLicenseDevicesParams, UpdateCouponParams, UpdateCustomerParams, UpdateProductGroupParams, UpdateProductParams, UpdateStoreCategoryParams, UsageCharge, ValidateLicenseParams, VerifyLicenseParams } from './types.js';
2
2
  export type * from './types.js';
3
- export declare const VERSION = "1.3.0";
3
+ export declare const VERSION = "1.4.0";
4
4
  export interface SkalpOptions {
5
5
  apiKey?: string;
6
6
  webhookSecret?: string;
@@ -79,7 +79,6 @@ export declare class Skalp {
79
79
  create: ({ email, name, note }: CreateCustomerParams) => Promise<Customer>;
80
80
  update: (id: string, { name, note }: UpdateCustomerParams) => Promise<Customer>;
81
81
  delete: (id: string) => Promise<Deleted>;
82
- adjustBalance: (id: string, { amount, reason }: AdjustCustomerBalanceParams) => Promise<Customer>;
83
82
  };
84
83
  readonly feedback: {
85
84
  list: ({ productId, rating, limit, offset }?: ListFeedbackParams) => Promise<FeedbackList>;
package/dist/cjs/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Skalp = exports.SkalpSignatureError = exports.SkalpConnectionError = exports.SkalpError = exports.VERSION = void 0;
4
- exports.VERSION = '1.3.0';
4
+ exports.VERSION = '1.4.0';
5
5
  const SIGNATURE_HEADER = 'skalp-signature';
6
6
  const SIGNATURE_TOLERANCE_SECONDS = 300;
7
7
  const USER_AGENT = `skalp-node/${exports.VERSION}`;
@@ -185,7 +185,6 @@ class Skalp {
185
185
  create: ({ email, name, note }) => this.#request('POST', '/v1/customers', { body: { email, name, note } }),
186
186
  update: (id, { name, note }) => this.#request('PATCH', `/v1/customers/${segment(id)}`, { body: { name, note } }),
187
187
  delete: (id) => this.#request('DELETE', `/v1/customers/${segment(id)}`),
188
- adjustBalance: (id, { amount, reason }) => this.#request('POST', `/v1/customers/${segment(id)}/balance`, { body: { amount, reason } }),
189
188
  };
190
189
  feedback = {
191
190
  list: ({ productId, rating, limit, offset } = {}) => this.#request('GET', '/v1/feedback', { query: { productId, rating, limit, offset } }),
@@ -60,6 +60,8 @@ export interface Order {
60
60
  deliveryStatus: DeliveryStatus | null;
61
61
  serialsCount?: number;
62
62
  serialsReplaced?: number;
63
+ /** Delivered and replaced keys by id, never their values. Only orders.get and orders.cancel fill it in. */
64
+ serials?: Array<OrderSerial>;
63
65
  createdAt: string;
64
66
  updatedAt: string;
65
67
  completedAt: string | null;
@@ -68,6 +70,14 @@ export interface Order {
68
70
  items?: Array<OrderItem>;
69
71
  replacements?: Array<OrderReplacement>;
70
72
  }
73
+ export interface OrderSerial {
74
+ id: string;
75
+ productId: string;
76
+ status: 'DELIVERED' | 'REPLACED';
77
+ deliveredAt: string | null;
78
+ /** The serial that took this one's place, once replaced. */
79
+ replacedById: string | null;
80
+ }
71
81
  export interface OrderReplacement {
72
82
  id: string;
73
83
  productId: string;
@@ -427,7 +437,6 @@ export interface Customer {
427
437
  name: string | null;
428
438
  note: string | null;
429
439
  country: string | null;
430
- balance: number;
431
440
  ordersCount: number;
432
441
  totalSpent: number;
433
442
  currency: Currency;
@@ -436,17 +445,8 @@ export interface Customer {
436
445
  createdAt: string;
437
446
  updatedAt: string;
438
447
  }
439
- export interface CustomerBalanceEntry {
440
- id: string;
441
- amount: number;
442
- balanceAfter: number;
443
- reason: string | null;
444
- orderId: string | null;
445
- createdAt: string;
446
- }
447
448
  export interface CustomerDetails extends Customer {
448
449
  recentOrders: Array<Order>;
449
- balanceHistory: Array<CustomerBalanceEntry>;
450
450
  }
451
451
  export interface ListCustomersParams {
452
452
  search?: string;
@@ -468,10 +468,6 @@ export interface UpdateCustomerParams {
468
468
  name?: string | null;
469
469
  note?: string | null;
470
470
  }
471
- export interface AdjustCustomerBalanceParams {
472
- amount: number;
473
- reason?: string;
474
- }
475
471
  export interface FeedbackReply {
476
472
  id: string;
477
473
  content: string;
@@ -869,19 +865,20 @@ export interface WebhookTestData {
869
865
  webhookId: string;
870
866
  sample: Partial<OrderPaidData>;
871
867
  }
872
- export type OrderEventData = Omit<Order, 'serialsCount' | 'serialsReplaced' | 'replacements'> & {
868
+ export type OrderEventData = Omit<Order, 'serialsCount' | 'serialsReplaced' | 'serials' | 'replacements'> & {
873
869
  previousStatus: OrderStatus | null;
870
+ /** Dedupe key: `order.created:<orderId>`, `order.updated:<orderId>:<transition>` or `order.canceled:<orderId>`. */
871
+ idempotencyKey: string;
874
872
  };
875
- export interface OrderReplacedData extends Omit<Order, 'serialsCount' | 'serialsReplaced' | 'replacements'> {
873
+ export interface OrderReplacedData extends Omit<Order, 'serialsCount' | 'serialsReplaced' | 'serials' | 'replacements'> {
874
+ /** Dedupe key: `order.replaced:<orderId>:<first new serial id>`. */
875
+ idempotencyKey: string;
876
876
  reason: string | null;
877
- replacements: Array<{
878
- productId: string;
879
- oldSerialId: string;
880
- newSerialId: string;
881
- key: string;
882
- }>;
877
+ replacements: Array<OrderKeyReplacement>;
883
878
  }
884
879
  export interface QueryEventData {
880
+ /** Dedupe key: `query.created:<queryId>` or `query.replied:<messageId>`. */
881
+ idempotencyKey: string;
885
882
  queryId: string;
886
883
  title: string;
887
884
  status: QueryStatus;
@@ -895,6 +892,8 @@ export interface QueryEventData {
895
892
  };
896
893
  }
897
894
  export interface FeedbackReceivedData {
895
+ /** Dedupe key: `feedback.received:<feedbackId>`. */
896
+ idempotencyKey: string;
898
897
  feedbackId: string;
899
898
  productId: string;
900
899
  productName: string;
@@ -1,6 +1,6 @@
1
- import type { AccessRule, AddAccessRuleParams, AddSerialsParams, AddSerialsResult, AdjustCustomerBalanceParams, AppealFeedbackParams, ChangeSubscriptionPlanParams, CheckoutSession, CheckoutSessionStatus, CoinCheckout, CoinCheckoutStatus, Coupon, CreateCheckoutParams, CreateCoinCheckoutParams, CreateCouponParams, CreateCustomerParams, CreateProductGroupParams, CreateProductParams, CreateStoreCategoryParams, CreateSubscriptionCheckoutParams, CreateUsageChargeParams, Customer, CustomerDetails, CustomerList, Deleted, Feedback, FeedbackList, HeartbeatParams, Invoice, LicenseKeyInfo, LicenseValidation, LicenseVerification, ListAccessRulesParams, ListCustomersParams, ListFeedbackParams, ListOrdersParams, ListProductsParams, ListQueriesParams, ListSerialsParams, ListSubscriptionsParams, Order, OrderKeysReplaced, OrderList, Product, ProductGroup, ProductStock, ReplaceOrderKeysParams, ReplyParams, SerialList, SkalpEvent, StoreCategory, StoreCategoryWithCount, Subscription, SubscriptionCheckout, SubscriptionCheckoutStatus, SubscriptionList, SupportQueryDetails, SupportQueryList, ResetLicenseDevicesParams, UpdateCouponParams, UpdateCustomerParams, UpdateProductGroupParams, UpdateProductParams, UpdateStoreCategoryParams, UsageCharge, ValidateLicenseParams, VerifyLicenseParams } from './types.js';
1
+ import type { AccessRule, AddAccessRuleParams, AddSerialsParams, AddSerialsResult, AppealFeedbackParams, ChangeSubscriptionPlanParams, CheckoutSession, CheckoutSessionStatus, CoinCheckout, CoinCheckoutStatus, Coupon, CreateCheckoutParams, CreateCoinCheckoutParams, CreateCouponParams, CreateCustomerParams, CreateProductGroupParams, CreateProductParams, CreateStoreCategoryParams, CreateSubscriptionCheckoutParams, CreateUsageChargeParams, Customer, CustomerDetails, CustomerList, Deleted, Feedback, FeedbackList, HeartbeatParams, Invoice, LicenseKeyInfo, LicenseValidation, LicenseVerification, ListAccessRulesParams, ListCustomersParams, ListFeedbackParams, ListOrdersParams, ListProductsParams, ListQueriesParams, ListSerialsParams, ListSubscriptionsParams, Order, OrderKeysReplaced, OrderList, Product, ProductGroup, ProductStock, ReplaceOrderKeysParams, ReplyParams, SerialList, SkalpEvent, StoreCategory, StoreCategoryWithCount, Subscription, SubscriptionCheckout, SubscriptionCheckoutStatus, SubscriptionList, SupportQueryDetails, SupportQueryList, ResetLicenseDevicesParams, UpdateCouponParams, UpdateCustomerParams, UpdateProductGroupParams, UpdateProductParams, UpdateStoreCategoryParams, UsageCharge, ValidateLicenseParams, VerifyLicenseParams } from './types.js';
2
2
  export type * from './types.js';
3
- export declare const VERSION = "1.3.0";
3
+ export declare const VERSION = "1.4.0";
4
4
  export interface SkalpOptions {
5
5
  apiKey?: string;
6
6
  webhookSecret?: string;
@@ -79,7 +79,6 @@ export declare class Skalp {
79
79
  create: ({ email, name, note }: CreateCustomerParams) => Promise<Customer>;
80
80
  update: (id: string, { name, note }: UpdateCustomerParams) => Promise<Customer>;
81
81
  delete: (id: string) => Promise<Deleted>;
82
- adjustBalance: (id: string, { amount, reason }: AdjustCustomerBalanceParams) => Promise<Customer>;
83
82
  };
84
83
  readonly feedback: {
85
84
  list: ({ productId, rating, limit, offset }?: ListFeedbackParams) => Promise<FeedbackList>;
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export const VERSION = '1.3.0';
1
+ export const VERSION = '1.4.0';
2
2
  const SIGNATURE_HEADER = 'skalp-signature';
3
3
  const SIGNATURE_TOLERANCE_SECONDS = 300;
4
4
  const USER_AGENT = `skalp-node/${VERSION}`;
@@ -179,7 +179,6 @@ export class Skalp {
179
179
  create: ({ email, name, note }) => this.#request('POST', '/v1/customers', { body: { email, name, note } }),
180
180
  update: (id, { name, note }) => this.#request('PATCH', `/v1/customers/${segment(id)}`, { body: { name, note } }),
181
181
  delete: (id) => this.#request('DELETE', `/v1/customers/${segment(id)}`),
182
- adjustBalance: (id, { amount, reason }) => this.#request('POST', `/v1/customers/${segment(id)}/balance`, { body: { amount, reason } }),
183
182
  };
184
183
  feedback = {
185
184
  list: ({ productId, rating, limit, offset } = {}) => this.#request('GET', '/v1/feedback', { query: { productId, rating, limit, offset } }),
@@ -60,6 +60,8 @@ export interface Order {
60
60
  deliveryStatus: DeliveryStatus | null;
61
61
  serialsCount?: number;
62
62
  serialsReplaced?: number;
63
+ /** Delivered and replaced keys by id, never their values. Only orders.get and orders.cancel fill it in. */
64
+ serials?: Array<OrderSerial>;
63
65
  createdAt: string;
64
66
  updatedAt: string;
65
67
  completedAt: string | null;
@@ -68,6 +70,14 @@ export interface Order {
68
70
  items?: Array<OrderItem>;
69
71
  replacements?: Array<OrderReplacement>;
70
72
  }
73
+ export interface OrderSerial {
74
+ id: string;
75
+ productId: string;
76
+ status: 'DELIVERED' | 'REPLACED';
77
+ deliveredAt: string | null;
78
+ /** The serial that took this one's place, once replaced. */
79
+ replacedById: string | null;
80
+ }
71
81
  export interface OrderReplacement {
72
82
  id: string;
73
83
  productId: string;
@@ -427,7 +437,6 @@ export interface Customer {
427
437
  name: string | null;
428
438
  note: string | null;
429
439
  country: string | null;
430
- balance: number;
431
440
  ordersCount: number;
432
441
  totalSpent: number;
433
442
  currency: Currency;
@@ -436,17 +445,8 @@ export interface Customer {
436
445
  createdAt: string;
437
446
  updatedAt: string;
438
447
  }
439
- export interface CustomerBalanceEntry {
440
- id: string;
441
- amount: number;
442
- balanceAfter: number;
443
- reason: string | null;
444
- orderId: string | null;
445
- createdAt: string;
446
- }
447
448
  export interface CustomerDetails extends Customer {
448
449
  recentOrders: Array<Order>;
449
- balanceHistory: Array<CustomerBalanceEntry>;
450
450
  }
451
451
  export interface ListCustomersParams {
452
452
  search?: string;
@@ -468,10 +468,6 @@ export interface UpdateCustomerParams {
468
468
  name?: string | null;
469
469
  note?: string | null;
470
470
  }
471
- export interface AdjustCustomerBalanceParams {
472
- amount: number;
473
- reason?: string;
474
- }
475
471
  export interface FeedbackReply {
476
472
  id: string;
477
473
  content: string;
@@ -869,19 +865,20 @@ export interface WebhookTestData {
869
865
  webhookId: string;
870
866
  sample: Partial<OrderPaidData>;
871
867
  }
872
- export type OrderEventData = Omit<Order, 'serialsCount' | 'serialsReplaced' | 'replacements'> & {
868
+ export type OrderEventData = Omit<Order, 'serialsCount' | 'serialsReplaced' | 'serials' | 'replacements'> & {
873
869
  previousStatus: OrderStatus | null;
870
+ /** Dedupe key: `order.created:<orderId>`, `order.updated:<orderId>:<transition>` or `order.canceled:<orderId>`. */
871
+ idempotencyKey: string;
874
872
  };
875
- export interface OrderReplacedData extends Omit<Order, 'serialsCount' | 'serialsReplaced' | 'replacements'> {
873
+ export interface OrderReplacedData extends Omit<Order, 'serialsCount' | 'serialsReplaced' | 'serials' | 'replacements'> {
874
+ /** Dedupe key: `order.replaced:<orderId>:<first new serial id>`. */
875
+ idempotencyKey: string;
876
876
  reason: string | null;
877
- replacements: Array<{
878
- productId: string;
879
- oldSerialId: string;
880
- newSerialId: string;
881
- key: string;
882
- }>;
877
+ replacements: Array<OrderKeyReplacement>;
883
878
  }
884
879
  export interface QueryEventData {
880
+ /** Dedupe key: `query.created:<queryId>` or `query.replied:<messageId>`. */
881
+ idempotencyKey: string;
885
882
  queryId: string;
886
883
  title: string;
887
884
  status: QueryStatus;
@@ -895,6 +892,8 @@ export interface QueryEventData {
895
892
  };
896
893
  }
897
894
  export interface FeedbackReceivedData {
895
+ /** Dedupe key: `feedback.received:<feedbackId>`. */
896
+ idempotencyKey: string;
898
897
  feedbackId: string;
899
898
  productId: string;
900
899
  productName: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skalpgg/sdk",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Official Skalp SDK for Node.js and edge runtimes: checkout, subscriptions, catalog and key stock, webhooks and license verification.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://skalp.gg/docs/sdk",