@usagetap/sdk 0.7.0 → 0.8.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
@@ -405,9 +405,10 @@ const { begin, end, vendor, endUsage } = envelope.data;
405
405
 
406
406
  Key exports from `@usagetap/sdk`:
407
407
 
408
- - `UsageTapClient` – minimal HTTP client for `createCustomer`, `changePlan`, `call_begin`, `call_end`, and `checkUsage`.
408
+ - `UsageTapClient` – minimal HTTP client for `createCustomer`, `changePlan`, `incrementCustomMeter`, `call_begin`, `call_end`, and `checkUsage`.
409
409
  - `createCustomer` – idempotently ensure a customer subscription exists before starting a call.
410
410
  - `changePlan` – switch a customer to a different usage plan with configurable strategy (immediate reset, prorated, or scheduled).
411
+ - `incrementCustomMeter` – track custom usage metrics beyond standard LLM counters (agent actions, documents, API calls, etc.).
411
412
  - `checkUsage` – lightweight method to query current usage status without creating a call session.
412
413
  - `wrapFetch` – wraps a fetch function to automatically instrument OpenAI API calls (minimal integration).
413
414
  - `createIdempotencyKey` – helper for generating UsageTap-compatible idempotency keys.
@@ -438,7 +439,7 @@ console.log("Plan:", snapshot.data.plan);
438
439
  console.log("Allowed entitlements:", snapshot.data.allowed);
439
440
  ```
440
441
 
441
- This returns the same rich subscription snapshot surfaces by `call_begin` and `checkUsage`, making it safe to cache the response for onboarding flows. Pass an `idempotencyKey` in `CreateCustomerOptions` when you need deterministic keys across services; otherwise the client auto-generates one by default.
442
+ This returns the same rich subscription snapshot surfaces by `call_begin` and `checkUsage`, making it safe to cache the response for onboarding flows. Pass `idempotencyKey` in `CreateCustomerOptions` when you need deterministic keys across services; otherwise the client auto-generates one by default. Both `idempotencyKey` (preferred) and `idempotency` (deprecated) are supported.
442
443
 
443
444
  ### Change a customer's plan
444
445
 
@@ -477,6 +478,78 @@ console.log("Balances:", usageStatus.data.balances);
477
478
 
478
479
  This returns the same rich usage snapshot as `call_begin` (meters, entitlements, subscription details, plan info, balances) but without creating a call record. Use this for dashboard widgets, pre-flight checks, or displaying quota status to users.
479
480
 
481
+ ### Increment custom meters
482
+
483
+ Custom meters allow you to track usage beyond standard LLM metrics—ideal for agent actions, document processing, API calls, or any custom usage you need to meter.
484
+
485
+ ```ts
486
+ const result = await usageTap.incrementCustomMeter({
487
+ customerId: "cust_123",
488
+ meterSlot: "CUSTOM1", // or "CUSTOM2"
489
+ amount: 5,
490
+ feature: "agent_actions",
491
+ tags: ["workflow_automation"],
492
+ metadata: {
493
+ workflowId: "wf_abc123",
494
+ actionType: "email_send",
495
+ },
496
+ });
497
+
498
+ console.log("Event recorded:", result.data.eventId);
499
+ console.log("Remaining quota:", result.data.meter.remaining);
500
+ console.log("Blocked:", result.data.blocked);
501
+ ```
502
+
503
+ **Parameters:**
504
+
505
+ - `customerId` (string, required): Customer identifier
506
+ - `meterSlot` ("CUSTOM1" | "CUSTOM2", required): Which custom meter to increment
507
+ - `amount` (number, required): Positive number to decrement from quota
508
+ - `feature` (string, optional): Feature identifier for tracking
509
+ - `tags` (string[], optional): Tags for categorization
510
+ - `metadata` (object, optional): Additional metadata
511
+
512
+ The method returns the updated meter snapshot showing remaining quota, limits, and usage. If the customer's plan has `limitType: "BLOCK"` and quota is exceeded, a `UsageTapError` is thrown with code `USAGETAP_AUTH_ERROR`.
513
+
514
+ **Use cases:**
515
+
516
+ ```ts
517
+ // Track agent tool invocations
518
+ await usageTap.incrementCustomMeter({
519
+ customerId: "cust_123",
520
+ meterSlot: "CUSTOM1",
521
+ amount: 1,
522
+ feature: "agent.tool_call",
523
+ tags: ["web_search"],
524
+ });
525
+
526
+ // Track document processing (10 pages)
527
+ await usageTap.incrementCustomMeter({
528
+ customerId: "cust_456",
529
+ meterSlot: "CUSTOM2",
530
+ amount: 10,
531
+ feature: "document.ocr",
532
+ metadata: { documentId: "doc_789", pages: 10 },
533
+ });
534
+
535
+ // Track external API calls
536
+ await usageTap.incrementCustomMeter({
537
+ customerId: "cust_789",
538
+ meterSlot: "CUSTOM1",
539
+ amount: 1,
540
+ feature: "external_api.maps",
541
+ tags: ["geocoding"],
542
+ });
543
+ ```
544
+
545
+ **Important notes:**
546
+
547
+ 1. Custom meters must be enabled in the customer's usage plan
548
+ 2. The `amount` decrements the remaining quota (like token usage)
549
+ 3. With `BLOCK` policy, exceeding quota throws an error
550
+ 4. With `DOWNGRADE` policy, usage continues but quota can go negative
551
+ 5. Unlimited meters don't track usage but still record events for analytics
552
+
480
553
  ## Response envelope (canonical only)
481
554
 
482
555
  UsageTap responds exclusively with the canonical `{ result, data, correlationId }` envelope for every endpoint. The SDK automatically sends `Accept: application/vnd.usagetap.v1+json`, parses the envelope, and returns strongly typed data structures. Transitional `raw` payloads and the `normalize*` helpers have been removed—`response.data` already contains the canonical shape you should persist or render.
@@ -1,5 +1,5 @@
1
1
  import OpenAI from 'openai';
2
- import { B as BeginCallRequest, U as UsageTapClient, W as WithUsageOptions, V as VendorHints, a as UsageTapSuccessResponse, b as BeginCallResponseBody, E as EndCallRequest } from '../client-nU5xk2pN.cjs';
2
+ import { B as BeginCallRequest, U as UsageTapClient, W as WithUsageOptions, V as VendorHints, a as UsageTapSuccessResponse, b as BeginCallResponseBody, E as EndCallRequest } from '../client-BzbMP-fp.cjs';
3
3
 
4
4
  interface OpenAIAdapterInit {
5
5
  client: OpenAI;
@@ -1,5 +1,5 @@
1
1
  import OpenAI from 'openai';
2
- import { B as BeginCallRequest, U as UsageTapClient, W as WithUsageOptions, V as VendorHints, a as UsageTapSuccessResponse, b as BeginCallResponseBody, E as EndCallRequest } from '../client-nU5xk2pN.js';
2
+ import { B as BeginCallRequest, U as UsageTapClient, W as WithUsageOptions, V as VendorHints, a as UsageTapSuccessResponse, b as BeginCallResponseBody, E as EndCallRequest } from '../client-BzbMP-fp.js';
3
3
 
4
4
  interface OpenAIAdapterInit {
5
5
  client: OpenAI;
@@ -1,6 +1,6 @@
1
1
  import { OpenAIAdapter } from './openai.cjs';
2
2
  import OpenAI from 'openai';
3
- import { U as UsageTapClient } from '../client-nU5xk2pN.cjs';
3
+ import { U as UsageTapClient } from '../client-BzbMP-fp.cjs';
4
4
 
5
5
  interface OpenRouterAdapterInit {
6
6
  client: OpenAI;
@@ -1,6 +1,6 @@
1
1
  import { OpenAIAdapter } from './openai.js';
2
2
  import OpenAI from 'openai';
3
- import { U as UsageTapClient } from '../client-nU5xk2pN.js';
3
+ import { U as UsageTapClient } from '../client-BzbMP-fp.js';
4
4
 
5
5
  interface OpenRouterAdapterInit {
6
6
  client: OpenAI;
@@ -26,6 +26,7 @@ interface MeterSummary {
26
26
  used: number | null;
27
27
  unlimited: boolean;
28
28
  ratio: number | null;
29
+ label?: string;
29
30
  }
30
31
  type MeterSnapshot = Record<string, MeterSummary>;
31
32
  type RemainingRatios = Record<string, number | null | undefined>;
@@ -64,7 +65,15 @@ interface BeginCallRequest {
64
65
  requested?: RequestedEntitlements;
65
66
  feature?: string;
66
67
  tags?: string[];
68
+ /**
69
+ * Idempotency key for safe retries. When omitted, UsageTap derives a key deterministically.
70
+ * @deprecated Use idempotencyKey instead
71
+ */
67
72
  idempotency?: string;
73
+ /**
74
+ * Idempotency key for safe retries. When omitted, UsageTap derives a key deterministically.
75
+ */
76
+ idempotencyKey?: string;
68
77
  customerName?: string;
69
78
  customerEmail?: string;
70
79
  stripeCustomerId?: string;
@@ -75,6 +84,8 @@ interface BalanceSummary {
75
84
  tokensRemaining?: number;
76
85
  searchesRemaining?: number;
77
86
  audioSecondsRemaining?: number;
87
+ customMeter1Remaining?: number;
88
+ customMeter2Remaining?: number;
78
89
  }
79
90
  interface PlanSummary {
80
91
  id: string | null;
@@ -283,6 +294,27 @@ interface ChangePlanResponseBody {
283
294
  success: boolean;
284
295
  subscription: SubscriptionSnapshot;
285
296
  }
297
+ type CustomMeterSlot = "CUSTOM1" | "CUSTOM2";
298
+ interface IncrementCustomMeterRequest {
299
+ customerId: string;
300
+ meterSlot: CustomMeterSlot;
301
+ amount: number;
302
+ feature?: string;
303
+ tags?: string[];
304
+ metadata?: Record<string, unknown>;
305
+ }
306
+ interface IncrementCustomMeterOptions extends RequestOptions {
307
+ correlationId?: string;
308
+ idempotencyKey?: string;
309
+ }
310
+ interface IncrementCustomMeterResponseBody {
311
+ success: boolean;
312
+ eventId: string;
313
+ meterSlot: CustomMeterSlot;
314
+ amount: number;
315
+ meter: MeterSummary;
316
+ blocked: boolean;
317
+ }
286
318
 
287
319
  declare class UsageTapClient {
288
320
  private readonly apiKey;
@@ -302,6 +334,7 @@ declare class UsageTapClient {
302
334
  checkUsage(request: CheckUsageRequest, options?: CheckUsageOptions): Promise<UsageTapSuccessResponse<CheckUsageResponseBody>>;
303
335
  createCustomer(request: CreateCustomerRequest, options?: CreateCustomerOptions): Promise<UsageTapSuccessResponse<CreateCustomerResponseBody>>;
304
336
  changePlan(request: ChangePlanRequest, options?: ChangePlanOptions): Promise<UsageTapSuccessResponse<ChangePlanResponseBody>>;
337
+ incrementCustomMeter(request: IncrementCustomMeterRequest, options?: IncrementCustomMeterOptions): Promise<UsageTapSuccessResponse<IncrementCustomMeterResponseBody>>;
305
338
  withUsage<T>(beginRequest: BeginCallRequest, handler: (context: WithUsageContext) => Promise<T>, options?: WithUsageOptions): Promise<T>;
306
339
  private request;
307
340
  private requestGet;
@@ -314,4 +347,4 @@ declare class UsageTapClient {
314
347
  private toApiError;
315
348
  }
316
349
 
317
- export { type AllowedEntitlements as A, type BeginCallRequest as B, type CreateCustomerOptions as C, type ModelHints as D, type EndCallRequest as E, type IdempotencyMetadata as I, type LimitType as L, type MeterSummary as M, type PlanSummary as P, type RemainingRatios as R, type SubscriptionSnapshot as S, UsageTapClient as U, type VendorHints as V, type WithUsageOptions as W, type UsageTapSuccessResponse as a, type BeginCallResponseBody as b, type BeginCallOptions as c, type CreateCustomerRequest as d, type CreateCustomerResponseBody as e, type CheckUsageOptions as f, type CheckUsageRequest as g, type CheckUsageResponseBody as h, type ChangePlanOptions as i, type ChangePlanRequest as j, type ChangePlanResponseBody as k, type ChangePlanStrategy as l, type EndCallOptions as m, type EndCallResponseBody as n, type BalanceSummary as o, type EntitlementHints as p, type MeterSnapshot as q, type MeteredUsage as r, type RequestedEntitlements as s, type RetryOptions as t, type UsageTapClientOptions as u, type UsageTapErrorResponse as v, type UsageTapResultEnvelope as w, type UsageTapResultStatus as x, type UsageTapLogEntry as y, type WithUsageContext as z };
350
+ export { type AllowedEntitlements as A, type BeginCallRequest as B, type CreateCustomerOptions as C, type UsageTapResultStatus as D, type EndCallRequest as E, type UsageTapLogEntry as F, type WithUsageContext as G, type ModelHints as H, type IncrementCustomMeterOptions as I, type IdempotencyMetadata as J, type LimitType as L, type MeterSummary as M, type PlanSummary as P, type RemainingRatios as R, type SubscriptionSnapshot as S, UsageTapClient as U, type VendorHints as V, type WithUsageOptions as W, type UsageTapSuccessResponse as a, type BeginCallResponseBody as b, type BeginCallOptions as c, type CreateCustomerRequest as d, type CreateCustomerResponseBody as e, type CheckUsageOptions as f, type CheckUsageRequest as g, type CheckUsageResponseBody as h, type ChangePlanOptions as i, type ChangePlanRequest as j, type ChangePlanResponseBody as k, type ChangePlanStrategy as l, type IncrementCustomMeterRequest as m, type IncrementCustomMeterResponseBody as n, type CustomMeterSlot as o, type EndCallOptions as p, type EndCallResponseBody as q, type BalanceSummary as r, type EntitlementHints as s, type MeterSnapshot as t, type MeteredUsage as u, type RequestedEntitlements as v, type RetryOptions as w, type UsageTapClientOptions as x, type UsageTapErrorResponse as y, type UsageTapResultEnvelope as z };
@@ -26,6 +26,7 @@ interface MeterSummary {
26
26
  used: number | null;
27
27
  unlimited: boolean;
28
28
  ratio: number | null;
29
+ label?: string;
29
30
  }
30
31
  type MeterSnapshot = Record<string, MeterSummary>;
31
32
  type RemainingRatios = Record<string, number | null | undefined>;
@@ -64,7 +65,15 @@ interface BeginCallRequest {
64
65
  requested?: RequestedEntitlements;
65
66
  feature?: string;
66
67
  tags?: string[];
68
+ /**
69
+ * Idempotency key for safe retries. When omitted, UsageTap derives a key deterministically.
70
+ * @deprecated Use idempotencyKey instead
71
+ */
67
72
  idempotency?: string;
73
+ /**
74
+ * Idempotency key for safe retries. When omitted, UsageTap derives a key deterministically.
75
+ */
76
+ idempotencyKey?: string;
68
77
  customerName?: string;
69
78
  customerEmail?: string;
70
79
  stripeCustomerId?: string;
@@ -75,6 +84,8 @@ interface BalanceSummary {
75
84
  tokensRemaining?: number;
76
85
  searchesRemaining?: number;
77
86
  audioSecondsRemaining?: number;
87
+ customMeter1Remaining?: number;
88
+ customMeter2Remaining?: number;
78
89
  }
79
90
  interface PlanSummary {
80
91
  id: string | null;
@@ -283,6 +294,27 @@ interface ChangePlanResponseBody {
283
294
  success: boolean;
284
295
  subscription: SubscriptionSnapshot;
285
296
  }
297
+ type CustomMeterSlot = "CUSTOM1" | "CUSTOM2";
298
+ interface IncrementCustomMeterRequest {
299
+ customerId: string;
300
+ meterSlot: CustomMeterSlot;
301
+ amount: number;
302
+ feature?: string;
303
+ tags?: string[];
304
+ metadata?: Record<string, unknown>;
305
+ }
306
+ interface IncrementCustomMeterOptions extends RequestOptions {
307
+ correlationId?: string;
308
+ idempotencyKey?: string;
309
+ }
310
+ interface IncrementCustomMeterResponseBody {
311
+ success: boolean;
312
+ eventId: string;
313
+ meterSlot: CustomMeterSlot;
314
+ amount: number;
315
+ meter: MeterSummary;
316
+ blocked: boolean;
317
+ }
286
318
 
287
319
  declare class UsageTapClient {
288
320
  private readonly apiKey;
@@ -302,6 +334,7 @@ declare class UsageTapClient {
302
334
  checkUsage(request: CheckUsageRequest, options?: CheckUsageOptions): Promise<UsageTapSuccessResponse<CheckUsageResponseBody>>;
303
335
  createCustomer(request: CreateCustomerRequest, options?: CreateCustomerOptions): Promise<UsageTapSuccessResponse<CreateCustomerResponseBody>>;
304
336
  changePlan(request: ChangePlanRequest, options?: ChangePlanOptions): Promise<UsageTapSuccessResponse<ChangePlanResponseBody>>;
337
+ incrementCustomMeter(request: IncrementCustomMeterRequest, options?: IncrementCustomMeterOptions): Promise<UsageTapSuccessResponse<IncrementCustomMeterResponseBody>>;
305
338
  withUsage<T>(beginRequest: BeginCallRequest, handler: (context: WithUsageContext) => Promise<T>, options?: WithUsageOptions): Promise<T>;
306
339
  private request;
307
340
  private requestGet;
@@ -314,4 +347,4 @@ declare class UsageTapClient {
314
347
  private toApiError;
315
348
  }
316
349
 
317
- export { type AllowedEntitlements as A, type BeginCallRequest as B, type CreateCustomerOptions as C, type ModelHints as D, type EndCallRequest as E, type IdempotencyMetadata as I, type LimitType as L, type MeterSummary as M, type PlanSummary as P, type RemainingRatios as R, type SubscriptionSnapshot as S, UsageTapClient as U, type VendorHints as V, type WithUsageOptions as W, type UsageTapSuccessResponse as a, type BeginCallResponseBody as b, type BeginCallOptions as c, type CreateCustomerRequest as d, type CreateCustomerResponseBody as e, type CheckUsageOptions as f, type CheckUsageRequest as g, type CheckUsageResponseBody as h, type ChangePlanOptions as i, type ChangePlanRequest as j, type ChangePlanResponseBody as k, type ChangePlanStrategy as l, type EndCallOptions as m, type EndCallResponseBody as n, type BalanceSummary as o, type EntitlementHints as p, type MeterSnapshot as q, type MeteredUsage as r, type RequestedEntitlements as s, type RetryOptions as t, type UsageTapClientOptions as u, type UsageTapErrorResponse as v, type UsageTapResultEnvelope as w, type UsageTapResultStatus as x, type UsageTapLogEntry as y, type WithUsageContext as z };
350
+ export { type AllowedEntitlements as A, type BeginCallRequest as B, type CreateCustomerOptions as C, type UsageTapResultStatus as D, type EndCallRequest as E, type UsageTapLogEntry as F, type WithUsageContext as G, type ModelHints as H, type IncrementCustomMeterOptions as I, type IdempotencyMetadata as J, type LimitType as L, type MeterSummary as M, type PlanSummary as P, type RemainingRatios as R, type SubscriptionSnapshot as S, UsageTapClient as U, type VendorHints as V, type WithUsageOptions as W, type UsageTapSuccessResponse as a, type BeginCallResponseBody as b, type BeginCallOptions as c, type CreateCustomerRequest as d, type CreateCustomerResponseBody as e, type CheckUsageOptions as f, type CheckUsageRequest as g, type CheckUsageResponseBody as h, type ChangePlanOptions as i, type ChangePlanRequest as j, type ChangePlanResponseBody as k, type ChangePlanStrategy as l, type IncrementCustomMeterRequest as m, type IncrementCustomMeterResponseBody as n, type CustomMeterSlot as o, type EndCallOptions as p, type EndCallResponseBody as q, type BalanceSummary as r, type EntitlementHints as s, type MeterSnapshot as t, type MeteredUsage as u, type RequestedEntitlements as v, type RetryOptions as w, type UsageTapClientOptions as x, type UsageTapErrorResponse as y, type UsageTapResultEnvelope as z };
@@ -1,6 +1,6 @@
1
1
  import OpenAI from 'openai';
2
2
  import { Request, Response, NextFunction } from 'express';
3
- import { U as UsageTapClient } from '../client-nU5xk2pN.cjs';
3
+ import { U as UsageTapClient } from '../client-BzbMP-fp.cjs';
4
4
  import { WrapOpenAIContext, WrapOpenAIOptions, wrapOpenAI, pipeToResponse } from '../adapters/openai.cjs';
5
5
 
6
6
  interface ExpressUsageTapContext {
@@ -1,6 +1,6 @@
1
1
  import OpenAI from 'openai';
2
2
  import { Request, Response, NextFunction } from 'express';
3
- import { U as UsageTapClient } from '../client-nU5xk2pN.js';
3
+ import { U as UsageTapClient } from '../client-BzbMP-fp.js';
4
4
  import { WrapOpenAIContext, WrapOpenAIOptions, wrapOpenAI, pipeToResponse } from '../adapters/openai.js';
5
5
 
6
6
  interface ExpressUsageTapContext {
package/dist/index.cjs CHANGED
@@ -121,6 +121,7 @@ var CALL_END_PATH = "call_end";
121
121
  var CHECK_USAGE_PATH = "customers/{customerId}/usage";
122
122
  var CREATE_CUSTOMER_PATH = "customers";
123
123
  var CHANGE_PLAN_PATH = "customers/{customerId}/change_plan";
124
+ var INCREMENT_CUSTOM_METER_PATH = "custom_meter";
124
125
  var AUTH_HEADER = "authorization";
125
126
  var API_KEY_HEADER = "x-api-key";
126
127
  var CORRELATION_HEADER = "x-usage-correlation-id";
@@ -128,7 +129,7 @@ var IDEMPOTENCY_HEADER = "idempotency-key";
128
129
  var SDK_HEADER = "x-usage-sdk";
129
130
  var USER_AGENT = "UsageTapClient";
130
131
  var CANONICAL_MEDIA_TYPE = "application/vnd.usagetap.v1+json";
131
- var SDK_VERSION = "0.7.0" ;
132
+ var SDK_VERSION = "0.8.0" ;
132
133
  var HAS_WINDOW = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
133
134
  var UsageTapClient = class {
134
135
  apiKey;
@@ -188,13 +189,14 @@ var UsageTapClient = class {
188
189
  this.autoIdempotency = options.autoIdempotency ?? true;
189
190
  }
190
191
  async beginCall(request, options = {}) {
191
- const idempotencyKey = request.idempotency ?? (this.autoIdempotency ? this.idempotencyGenerator() : void 0);
192
+ const idempotencyKey = request.idempotencyKey ?? request.idempotency ?? (this.autoIdempotency ? this.idempotencyGenerator() : void 0);
192
193
  const payload = {
193
194
  ...request,
194
195
  feature: request.feature ?? this.defaultFeature,
195
196
  tags: this.mergeTags(request.tags)
196
197
  };
197
198
  if (idempotencyKey) {
199
+ payload.idempotencyKey = idempotencyKey;
198
200
  payload.idempotency = idempotencyKey;
199
201
  }
200
202
  const response = await this.request(
@@ -289,9 +291,59 @@ var UsageTapClient = class {
289
291
  );
290
292
  return response;
291
293
  }
294
+ async incrementCustomMeter(request, options = {}) {
295
+ if (!request?.customerId) {
296
+ throw new UsageTapError(
297
+ "USAGETAP_BAD_REQUEST",
298
+ "incrementCustomMeter requires customerId"
299
+ );
300
+ }
301
+ if (!request?.meterSlot) {
302
+ throw new UsageTapError(
303
+ "USAGETAP_BAD_REQUEST",
304
+ "incrementCustomMeter requires meterSlot"
305
+ );
306
+ }
307
+ if (!["CUSTOM1", "CUSTOM2"].includes(request.meterSlot)) {
308
+ throw new UsageTapError(
309
+ "USAGETAP_BAD_REQUEST",
310
+ "meterSlot must be CUSTOM1 or CUSTOM2"
311
+ );
312
+ }
313
+ if (typeof request.amount !== "number" || !Number.isFinite(request.amount) || request.amount <= 0) {
314
+ throw new UsageTapError(
315
+ "USAGETAP_BAD_REQUEST",
316
+ "incrementCustomMeter requires a positive numeric amount"
317
+ );
318
+ }
319
+ const idempotencyKey = options.idempotencyKey ?? (this.autoIdempotency ? this.idempotencyGenerator() : void 0);
320
+ const payload = {
321
+ customerId: request.customerId,
322
+ meterSlot: request.meterSlot,
323
+ amount: request.amount
324
+ };
325
+ if (request.feature) {
326
+ payload.feature = request.feature;
327
+ }
328
+ if (request.tags && request.tags.length > 0) {
329
+ payload.tags = request.tags;
330
+ }
331
+ if (request.metadata) {
332
+ payload.metadata = request.metadata;
333
+ }
334
+ const response = await this.request(
335
+ INCREMENT_CUSTOM_METER_PATH,
336
+ payload,
337
+ {
338
+ ...options,
339
+ idempotencyKey
340
+ }
341
+ );
342
+ return response;
343
+ }
292
344
  async withUsage(beginRequest, handler, options = {}) {
293
- const idempotencyKey = beginRequest.idempotency ?? (this.autoIdempotency ? this.idempotencyGenerator() : void 0);
294
- const beginPayload = idempotencyKey ? { ...beginRequest, idempotency: idempotencyKey } : { ...beginRequest };
345
+ const idempotencyKey = beginRequest.idempotencyKey ?? beginRequest.idempotency ?? (this.autoIdempotency ? this.idempotencyGenerator() : void 0);
346
+ const beginPayload = idempotencyKey ? { ...beginRequest, idempotencyKey, idempotency: idempotencyKey } : { ...beginRequest };
295
347
  const beginResponse = await this.beginCall(beginPayload, options);
296
348
  let usage = {};
297
349
  const initialStripeCustomerId = typeof beginResponse.data.stripeCustomerId === "string" ? beginResponse.data.stripeCustomerId : typeof beginRequest.stripeCustomerId === "string" ? beginRequest.stripeCustomerId : void 0;