> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stigg.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Usage, billing & credits

> Report usage, estimate costs, manage credits, promotions, and coupons using Stigg backend SDKs.

## Usage reporting

The Stigg SDK allows you to report usage measurements for [metered features](/documentation/modeling-your-pricing-in-stigg/features/overview). The reported usage is used to track, limit, and bill the customer's usage of metered features.

<Warning>
  1. Report usage only after the relevant resources have been provisioned in your application.
  2. Ensure customers are not allowed to allocate new resources until an acknowledgement about the processed measurement is received from the Stigg backend.
</Warning>

### Calculated usage

Report pre-aggregated usage values calculated by your application. This is useful for features like seats or storage.

You provide the customer ID, the metered feature ID, and the usage value. Optionally, specify a resource ID and update behavior - by default the value represents the **change** in usage (delta), but you can also set the usage to an absolute value.

<CodeGroup>
  ```javascript Node.js theme={null}
  // increment usage of a metered feature by 10
  await stiggClient.reportUsage({
    customerId: 'customer-test-id',
    featureId: 'feature-seats',
    value: 10,
    resourceId: 'resource-01',      // optional
  });
  ```

  ```python Python theme={null}
  data = await client.report_usage(ReportUsageInput(
      **{
          "value": 5,
          "customerId": "customer-id",
          "featureId": "feature-02-campaigns",
          "resourceId": "resource-01",  # optional
      }
    ))
  ```

  ```go Go theme={null}
  result, err := client.ReportUsage(context.Background(), stigg.ReportUsageInput{
    Value:      5,
    CustomerID: "customer-demo-01",
    FeatureID:  "feature-02-campaigns",
    ResourceID: Ptr("resource-01"),  // optional
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Mutation::ReportUsage, {
      "input": {
          "value": 5,
          "customerId": "customer-id",
          "featureId": "feature-02-campaigns",
          "resourceId": "resource-01",  # optional
      }
  })
  ```

  ```java Java theme={null}
  var resp =
    stigg.mutation(
      ReportUsageMutation.builder()
      .input(
        ReportUsageInput.builder()
        .customerId("customer-demo-01")
        .featureId("feature-seats")
        .value(1.0)
        .resourceId("resource-01") // optional
        .build())
      .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.ReportUsage.ExecuteAsync(new ReportUsageInput()
  {
    CustomerId = "customer-demo-01",
    FeatureId = "feature-seats",
    Value = 1,
    ResourceId = "resource-01" // optional
  });
  ```
</CodeGroup>

<Expandable title="Result (Node.js)">
  ```json theme={null}
  {
    "measurementId": "e7293df0-2d69-4713-9913-10ed06b9b777"
  }
  ```
</Expandable>

#### Synchronous credit balance updates

When the reported feature is credit-backed, `reportUsage` also returns a `credit` object in the response containing the updated credit balance — immediately, before the asynchronous metering pipeline completes. The deduction is applied optimistically (write-back cache strategy): the response reflects the balance as if the usage has already settled, and reconciliation to the exact source-of-truth value happens in the background.

This makes `reportUsage` the right choice for **strict, real-time credit enforcement** (e.g., AI token consumption, per-call API billing), while `reportEvent` remains the choice for **high-volume, eventually-consistent** use cases.

|                                | `reportUsage`                    | `reportEvent`                                 |
| ------------------------------ | -------------------------------- | --------------------------------------------- |
| **Latency**                    | Sub-second                       | \~10 seconds                                  |
| **Credit balance in response** | Yes — optimistic, immediate      | No                                            |
| **Volume**                     | Lower                            | Higher                                        |
| **Best for**                   | Strict enforcement, real-time UX | High-volume metering, less strict enforcement |

<Expandable title="Result — credit-backed feature (Node.js)">
  ```json theme={null}
  {
    "measurementId": "e7293df0-2d69-4713-9913-10ed06b9b777",
    "credit": {
      "currencyId": "currency-tokens",
      "currentUsage": 3500,
      "usageLimit": 10000,
      "timestamp": "2026-06-23T12:01:45.000Z"
    }
  }
  ```

  `currentUsage` is the total credits consumed so far. `usageLimit` is the total granted. Remaining balance = `usageLimit - currentUsage`.
</Expandable>

Calculated usage can also be reported in bulk.

### Raw events

Report raw events from your application, which Stigg filters and aggregates to calculate customer usage. This is useful for features like monthly active users (MAUs).

You provide the customer ID, event name, and an idempotency key for deduplication. Optionally, include dimensions (key-value pairs for filtering and aggregation), a resource ID, and a timestamp.

<CodeGroup>
  ```javascript Node.js theme={null}
  await stiggClient.reportEvent({
    customerId: 'customer-test-id',
    resourceId: 'resource-01',      // optional
    eventName: 'user_login',
    idempotencyKey: '227c1b73-883a-457b-b715-6ba5a2c69ce4',
    dimensions: {
      user_id: 'user-01',
      user_email: 'john@example.com'
      },
    timestamp: '2022-10-26T15:01:55.768Z' // optional
  });
  ```

  ```python Python theme={null}
  data = await client.report_event(UsageEventsReportInput(
      ** {
          "usageEvents": [{
              "customerId": "customer-test-id",
              "resourceId": "resource-01",      # optional
              "eventName": "user_login",
              "idempotencyKey": "227c1b73-883a-457b-b715-6ba5a2c69ce4",
              "dimensions": {
                  "user_id": "user-01",
                  "user_email": "john@example.com"
              },
              "timestamp": "2022-10-26T15:01:55.768Z" # optional
          }]
       }
  ))
  ```

  ```go Go theme={null}
  result, err := client.ReportEvent(context.Background(), stigg.UsageEventsReportInput{
    UsageEvents: []*stigg.UsageEventReportInput{
      {
        CustomerID:     "customer-test-id",
        ResourceID:     Ptr("resource-01"), // optional
        EventName:      "user_login",
        IdempotencyKey: "227c1b73-883a-457b-b715-6ba5a2c69ce4",
        Dimensions: map[string]interface{}{
          "user_id":    "user-01",
          "user_email": "john@example.com",
        },
        Timestamp: Ptr("2022-10-26T15:01:55.768Z"), // optional
      },
    },
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Mutation::ReportEvent, {
      "input": {
          "usageEvents": [{
              "customerId": "customer-test-id",
              "resourceId": "resource-01",      # optional
              "eventName": "user_login",
              "idempotencyKey": "227c1b73-883a-457b-b715-6ba5a2c69ce4",
              "dimensions": {
                  "user_id": "user-01",
                  "user_email": "john@example.com"
              },
              "timestamp": "2022-10-26T15:01:55.768Z" # optional
          }]
      }
  })
  ```

  ```java Java theme={null}
  var resp =
    stigg.mutation(
      ReportEventMutation.builder()
      .input(
        UsageEventsReportInput.builder()
        .usageEvents(List.of(
          UsageEventReportInput.builder()
          .customerId("customer-test-id")
          .eventName("user_login")
          .idempotencyKey("227c1b73-883a-457b-b715-6ba5a2c69ce4")
          .timestamp(Instant.now())
          .dimensions(new HashMap<>() {{
            put("user_id", "user-01");
            put("user_email", "john@example.com");
          }})
          .resourceId("resource-01") // optional
          .build()
        ))
        .build())
      .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.ReportEvent.ExecuteAsync(new UsageEventsReportInput()
  {
    UsageEvents = new List<UsageEventReportInput>()
    {
      new()
      {
        CustomerId = "customer-test-id",
        EventName = "user_login",
        Dimensions = JsonSerializer.SerializeToElement(new { user_id = "user-01" }),
        IdempotencyKey = Guid.NewGuid().ToString(),
      }
    }
  });
  ```
</CodeGroup>

Events can also be sent in batches.

<Card title="Metering and aggregation capabilities" icon="gauge" horizontal href="/documentation/getting-usage-data-into-stigg/overview" />

## Paywall data

Retrieve paywall data for rendering a public pricing page or customer-facing paywall. Returns plans with their entitlements, pricing, trial configurations, compatible add-ons, and product metadata.

<CodeGroup>
  ```javascript Node.js theme={null}
  const paywallData = await stiggClient.getPaywall();
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Query::GetPaywall, { 'input': {} })
  ```

  ```java Java theme={null}
  var resp = stigg.query(GetPaywallQuery.builder()
                         .input(GetPaywallInput.builder()
                                .productId("product-revvenu")   // optional
                                .customerId("customer-demo-01") // optional
                                .resourceId("resource-01")      // optional
                                .billingCountryCode("US")       // optional
                                .build())
                         .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.GetPaywall.ExecuteAsync(new GetPaywallInput()
  {
    ProductId = "product-revvenu",          // optional
    CustomerId = "customer-demo-01",        // optional
    ResourceId = "resource-01",             // optional
    BillingCountryCode = "US",              // optional
    FetchAllCountriesPrices = false         // optional
  });
  ```
</CodeGroup>

## Cost estimation

### Estimating new subscription cost

Estimate the cost of a new subscription before the customer commits. Useful for displaying pricing previews.

<CodeGroup>
  ```javascript Node.js theme={null}
  await stiggClient.estimateSubscription({
    customerId: "customer-demo-01",
    billingPeriod: "MONTHLY",
    planId: "plan-revvenu-growth",
    billableFeatures: [{ 						// optional, required for per-unit pricing
      featureId:'feature-01-templates',
      quantity: 2
    }],
    addons: [{  								// optional
    	addonId: 'addon-10-campaigns',
      quantity: 1
    }],
    promotionCode: "STIGG50",		// optional
    startDate: new Date(), 			// optional
    billingCountryCode: 'US', 	// optional, required for price localization
    resourceId: 'resource-01',  // optional, required for multiple subscriptions
  });
  ```

  ```python Python theme={null}
  data = await client.request(EstimateSubscriptionInput(
      ** {
          "customerId": "customer-demo-01",
          "billingPeriod": "MONTHLY",
          "planId": "plan-revvenu-essentials",
        	"billableFeatures": [{								# optional
            "featureId": "feature-01-templates",
            "quantity": 2
          }],
          "addons": [														# optional
              {
                  "addonId": "addon-10-campaigns",
                  "quantity": 2
              }
          ],
          "billingCountryCode": "DK",  # optional, required for price localization
          "resourceId": "resource-01",  # optional
      }
  ))
  ```

  ```go Go theme={null}
  result, err := client.EstimateSubscription(context.Background(), stigg.EstimateSubscriptionInput{
      CustomerID:      "customer-demo-01",
      PlanID:          "plan-revvenu-essentials",
      BillingPeriod:   Ptr(stigg.BillingPeriodMonthly),
      PriceUnitAmount: Ptr(float64(4)), // optional, required for per-unit pricing
      Addons: []*stigg.SubscriptionAddonInput{{ // optional
        AddonID:  "addon-10-campaigns",
        Quantity: Ptr(int64(5)),
      }},
      BillingCountryCode: Ptr("DK"),          // optional, required for price localization
      ResourceID:         Ptr("resource-01"), // optional
    })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Mutation::EstimateSubscription, {
      "input": {
          "customerId": "customer-demo-01",
          "billingPeriod": "MONTHLY",
          "planId": "plan-revvenu-essentials",
        	"billableFeatures": [{			 # optional
            "featureId": "feature-01-templates",
            "quantity": 4
          }],
          "addons": [									 # optional
              {
                  "addonId": "addon-10-campaigns",
                  "quantity": 2
              }
          ],
        	"billingCountryCode": "DK",   # optional, required for price localization
          "resourceId": "resource-01",  # optional
      }
  })
  ```

  ```java Java theme={null}
  var resp =
    stigg.mutation(
      EstimateSubscriptionMutation.builder()
      .input(
        EstimateSubscriptionInput.builder()
        .customerId("customer-demo-01")
        .billingPeriod(BillingPeriod.MONTHLY)
        .planId("plan-revvenu-essentials")
        .billableFeatures(
          List.of(
            BillableFeatureInput.builder()
            .featureId("feature-01-templates")
            .quantity(5.0)
            .build()))
        .addons(
          List.of(
            SubscriptionAddonInput.builder()
            .addonId("addon-10-campaigns")
            .quantity(5)
            .build()))
        .billingCountryCode("DK")        // optional, required for price localization
        .resourceId("resource-01")       // optional
        .build())
      .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.EstimateSubscription.ExecuteAsync(new EstimateSubscriptionInput()
  {
    CustomerId = "customer-demo-01",
    PlanId = "plan-revvenu-essentials",
    BillableFeatures = new List<BillableFeatureInput>()
    {
      new()
      {
        FeatureId = "feature-01-templates",
        Quantity = 5
      }
    },
    Addons = new List<SubscriptionAddonInput>()
    {
      new()
      {
        AddonId = "addon-10-campaigns",
        Quantity = 5
      }
    },
  });
  ```
</CodeGroup>

The response includes a cost breakdown (total, subtotal, tax), applied discount details (type, value, duration), the billing period date range, and prorated credit/debit amounts.

<Expandable title="Result (Node.js)">
  ```json theme={null}
  {
    "total": {
      "amount": 10,
      "currency": "USD"
    },
    "subTotal": {
      "amount": 10,
      "currency": "USD"
    },
    "billingPeriodRange": {
      "start": "2022-10-26T00:00:00.000Z",
      "end": "2022-11-26T00:00:00.000Z"
    },
    "discount": {
      "type": "PERCENTAGE",
      "value": 50,
      "durationType": "REPEATING",
      "durationInMonths": 3
    },
    "proration": {
      "credit": {
        "amount": 0,
        "currency": "USD"
      },
      "debit": {
        "amount": 10,
        "currency": "USD"
      },
      "netAmount": {
        "amount": 10,
        "currency": "USD"
      },
      "prorationDate": "2022-10-26T00:00:00.000Z"
    }
  }
  ```
</Expandable>

### Estimating subscription update cost

Estimate the cost of updating an existing subscription (e.g., changing seat count or add-ons), including a proration breakdown.

<Warning>
  Promo code support requires an integration with a billing solution such as [Stripe](/documentation/native-integrations/billing/stripe/integration-when-using-stripe-elements-for-checkout). Promo codes must be generated in the integrated billing solution.
</Warning>

<CodeGroup>
  ```javascript Node.js theme={null}
  await stiggClient.estimateSubscriptionUpdate({
    subscriptionId: "subscription-plan-revvenu-growth-da6324",
    billableFeatures: [{ // optional
      featureId: 'feature-01-templates',
      quantity: 3
    }],
    addons: [{ // optional
      addonId: 'addon-10-campaigns',
      quantity: 1
    }],
    promotionCode: "STIGG50" // optional
  });
  ```

  ```python Python theme={null}
  data = await client.estimate_subscription_update(EstimateSubscriptionUpdateInput(
    **{
      "subscriptionId": "subscription-plan-revvenu-growth-dfe598",
      "billableFeatures": [{"featureId": "feature-01-templates", "quantity": 7}],
      "addons": [{"addonId": "addon-10-campaigns", "quantity": 2}]
    }
  ))
  ```

  ```go Go theme={null}
  result, err := client.EstimateSubscriptionUpdate(context.Background(), stigg.EstimateSubscriptionUpdateInput{
    SubscriptionID: "subscription-plan-revvenu-basic-558071",
    UnitQuantity:   Ptr(float64(4)),
    Addons: []*stigg.SubscriptionAddonInput{{
      AddonID:  "addon-10-campaigns",
      Quantity: Ptr(int64(5)),
    }},
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Mutation::EstimateSubscriptionUpdate, {
    "input": {
      "subscriptionId": "subscription-plan-revvenu-growth-dfe598",
      "billableFeatures": [{"featureId": "feature-01-templates", "quantity": 7}],
      "addons": [{"addonId": "addon-10-campaigns", "quantity": 2}]
    }
  })
  ```

  ```java Java theme={null}
  var resp = stigg.mutation(
    EstimateSubscriptionUpdateMutation.builder()
    .input(
      EstimateSubscriptionUpdateInput.builder()
      .subscriptionId("subscription-plan-revvenu-essentials-bum2flivze")
      .billableFeatures(List.of(
        BillableFeatureInput.builder()
        .featureId("feature-01-templates")
        .quantity(5.0)
        .build()))
      .addons(List.of(
        SubscriptionAddonInput.builder()
        .addonId("addon-10-campaigns")
        .quantity(5)
        .build()))
      .build())
    .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.EstimateSubscriptionUpdate.ExecuteAsync(new EstimateSubscriptionUpdateInput()
  {
    SubscriptionId = "subscription-plan-revvenu-essentials-bum2flivze",
    BillableFeatures = new List<BillableFeatureInput>()
    {
      new() { FeatureId = "feature-01-templates", Quantity = 5 }
    },
    Addons = new List<SubscriptionAddonInput>()
    {
      new() { AddonId = "addon-10-campaigns", Quantity = 5 }
    },
  });
  ```
</CodeGroup>

## Promotional entitlements

### Granting promotional entitlements

Grant time-limited or custom-period [promotional entitlements](/documentation/managing-customers-and-subscriptions/customers/managing-customers-promotional-entitlements) to customers, with optional usage limits and reset periods.

<CodeGroup>
  ```javascript Node.js theme={null}
  // Use the grantPromotionalEntitlements method — see the Node.js SDK reference for full usage:
  // https://node-sdk-docs.stigg.io/classes/stigg#grantpromotionalentitlements
  ```

  ```python Python theme={null}
  data = await client.grant_promotional_entitlements(GrantPromotionalEntitlementsInput(**{
    "customer_id": "customer-demo-01",
    "promotional_entitlements": [
      {
        "feature_id": "feature-04-analytics",
        "period": "ONE_MONTH",
      },
      {
        "feature_id": "feature-03-memory",
        "period": "CUSTOM",
        "custom_end_date": "2023-10-26T15:01:55.768Z",
        "usage_limit": 100
      }
    ]
  }))
  ```

  ```java Java theme={null}
  var resp = stigg.mutation(
    GrantPromotionalEntitlementsMutation.builder()
    .input(
      GrantPromotionalEntitlementsInput.builder()
      .customerId("customer-demo-01")
      .promotionalEntitlements(List.of(
        GrantPromotionalEntitlementInput.builder()
        .featureId("feature-04-analytics")
        .period(PromotionalEntitlementPeriod.ONE_MONTH)
        .build(),
        GrantPromotionalEntitlementInput.builder()
        .featureId("feature-02-campaigns")
        .period(PromotionalEntitlementPeriod.CUSTOM)
        .customEndDate(Instant.now().atZone(ZoneId.of("UTC")).plusDays(30).toInstant())
        .usageLimit(100.0)
        .build()
      ))
      .build())
    .build()
  );
  ```

  ```c# .NET theme={null}
  var resp = await stigg.GrantPromotionalEntitlements.ExecuteAsync(new GrantPromotionalEntitlementsInput()
  {
    CustomerId = "customer-demo-01",
    PromotionalEntitlements = new List<GrantPromotionalEntitlementInput>()
    {
      new()
      {
        FeatureId = "feature-04-analytics",
        Period = PromotionalEntitlementPeriod.Lifetime
      },
      new()
      {
        FeatureId = "feature-02-campaigns",
        Period = PromotionalEntitlementPeriod.Custom,
        CustomEndDate = DateTime.Now.AddDays(15),
        UsageLimit = 100
      }
    }
  });
  ```
</CodeGroup>

### Revoking promotional entitlements

Revoke previously granted promotional entitlements from a customer.

<CodeGroup>
  ```javascript Node.js theme={null}
  // Use the revokePromotionalEntitlements method — see the Node.js SDK reference for full usage:
  // https://node-sdk-docs.stigg.io/classes/stigg#revokepromotionalentitlements
  ```

  ```python Python theme={null}
  data = await client.revoke_promotional_entitlement(RevokePromotionalEntitlementInput(**{
    "customer_id": "customer-demo-01",
    "feature_id": "feature-04-analytics",
  }))
  ```

  ```java Java theme={null}
  var resp = stigg.mutation(
    RevokePromotionalEntitlementMutation.builder()
    .input(
      RevokePromotionalEntitlementInput.builder()
      .featureId("feature-04-analytics")
      .customerId("customer-demo-01")
      .build()
    )
    .build());
  ```

  ```c# .NET theme={null}
  await stigg.RevokePromotionalEntitlement.ExecuteAsync(new RevokePromotionalEntitlementInput()
  {
    CustomerId = "customer-demo-01",
    FeatureId = "feature-04-analytics"
  });
  ```
</CodeGroup>

## Coupons

Retrieve available coupons, including their discount values, types, and metadata.

<CodeGroup>
  ```javascript Node.js theme={null}
  const coupons = await stiggClient.getCoupons();
  ```

  ```python Python theme={null}
  data = await client.get_coupons()
  ```

  ```go Go theme={null}
  result, err := client.GetCoupons(context.Background())
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Query::GetCoupons, {})
  ```

  ```java Java theme={null}
  var resp = stigg.query(GetCouponsQuery.builder().build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.GetCoupons.ExecuteAsync();
  ```
</CodeGroup>

## Credits

### Grant credits

Grant credits to a customer's credit pool. Set `grantType` to `PAID` for purchased credits or `PROMOTIONAL` for free or incentive credits. Pass `resourceId` to credit a [resource-specific pool](/documentation/modeling-your-pricing-in-stigg/credits/resource-specific-pools) rather than the global pool.

<CodeGroup>
  ```javascript Node.js theme={null}
  await stiggClient.createCreditGrant({
    customerId: 'customer-demo-01',
    currencyId: 'ai-tokens',
    displayName: 'Onboarding bonus',
    amount: 1000,
    grantType: 'PROMOTIONAL',
    resourceId: 'workspace-example-com', // optional — scope to a resource pool
    effectiveAt: new Date(),             // optional
    expireAt: new Date('2026-12-31'),    // optional
    comment: 'Welcome promotion',        // optional
  });
  ```

  ```python Python theme={null}
  from stigg.types import CreateCreditGrantMutation, CreditGrantInput

  result = await client.mutation(
      CreateCreditGrantMutation,
      {
          "input": {
              "customerId": "customer-demo-01",
              "currencyId": "ai-tokens",
              "displayName": "Onboarding bonus",
              "amount": 1000,
              "grantType": "PROMOTIONAL",
              "resourceId": "workspace-example-com",  # optional
              "expireAt": "2026-12-31T00:00:00Z",     # optional
          }
      },
  )
  ```

  ```go Go theme={null}
  result, err := client.CreateCreditGrant(context.Background(), stigg.CreditGrantInput{
    CustomerID:  "customer-demo-01",
    CurrencyID:  "ai-tokens",
    DisplayName: "Onboarding bonus",
    Amount:      1000,
    GrantType:   stigg.CreditGrantTypeInputPromotional,
    ResourceID:  Ptr("workspace-example-com"), // optional
    ExpireAt:    Ptr(time.Date(2026, 12, 31, 0, 0, 0, 0, time.UTC)), // optional
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Mutation::CreateCreditGrant, {
    "input": {
      "customerId": "customer-demo-01",
      "currencyId": "ai-tokens",
      "displayName": "Onboarding bonus",
      "amount": 1000,
      "grantType": "PROMOTIONAL",
      "resourceId": "workspace-example-com",  # optional
    }
  })
  ```

  ```java Java theme={null}
  var resp = stigg.mutation(
    CreateCreditGrantMutation.builder()
    .input(
      CreditGrantInput.builder()
      .customerId("customer-demo-01")
      .currencyId("ai-tokens")
      .displayName("Onboarding bonus")
      .amount(1000.0)
      .grantType(CreditGrantTypeInput.PROMOTIONAL)
      .resourceId("workspace-example-com") // optional
      .build()
    )
    .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.CreateCreditGrant.ExecuteAsync(new CreditGrantInput()
  {
    CustomerId = "customer-demo-01",
    CurrencyId = "ai-tokens",
    DisplayName = "Onboarding bonus",
    Amount = 1000,
    GrantType = CreditGrantTypeInput.Promotional,
    ResourceId = "workspace-example-com", // optional
  });
  ```
</CodeGroup>

### Void credit grant

Cancel an active credit grant by its ID. Any remaining credits in the grant are immediately removed from the customer's balance.

<CodeGroup>
  ```javascript Node.js theme={null}
  await stiggClient.voidCreditGrant({ id: 'grant-abc123' });
  ```

  ```python Python theme={null}
  from stigg.types import VoidCreditGrantMutation

  result = await client.mutation(
      VoidCreditGrantMutation,
      {"input": {"id": "grant-abc123"}},
  )
  ```

  ```go Go theme={null}
  result, err := client.VoidCreditGrant(context.Background(), stigg.VoidCreditGrantInput{
    ID: "grant-abc123",
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Mutation::VoidCreditGrant, {
    "input": { "id": "grant-abc123" }
  })
  ```

  ```java Java theme={null}
  var resp = stigg.mutation(
    VoidCreditGrantMutation.builder()
    .input(VoidCreditGrantInput.builder().id("grant-abc123").build())
    .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.VoidCreditGrant.ExecuteAsync(new VoidCreditGrantInput()
  {
    Id = "grant-abc123"
  });
  ```
</CodeGroup>

### Query credit usage

Retrieve a customer's credit consumption history as a time-series. Use `timeRange` for preset windows or `startDate`/`endDate` for an exact range. Break down consumption by any dimension key from your usage events using `groupBy` (up to 3 keys). Pass `resourceId` to scope the query to a specific resource pool.

<CodeGroup>
  ```javascript Node.js theme={null}
  // By preset time range
  const usage = await stiggClient.getCreditUsage({
    customerId: 'customer-demo-01',
    currencyId: 'ai-tokens',         // optional — defaults to first active currency
    timeRange: 'LAST_MONTH',         // LAST_DAY | LAST_WEEK | LAST_MONTH | LAST_YEAR
    resourceId: 'workspace-example-com', // optional
  });

  // By exact date range, broken down by model dimension
  const usageByModel = await stiggClient.getCreditUsage({
    customerId: 'customer-demo-01',
    startDate: new Date('2026-05-01'),
    endDate: new Date('2026-05-31'),
    groupBy: ['model'],              // any dimension key from your usage events
  });
  ```

  ```python Python theme={null}
  from stigg.types import CreditUsageQuery

  # By preset time range
  result = await client.query(
      CreditUsageQuery,
      {
          "input": {
              "customerId": "customer-demo-01",
              "currencyId": "ai-tokens",
              "timeRange": "LAST_MONTH",
              "resourceId": "workspace-example-com",  # optional
          }
      },
  )

  # By exact date range with dimension breakdown
  result = await client.query(
      CreditUsageQuery,
      {
          "input": {
              "customerId": "customer-demo-01",
              "startDate": "2026-05-01T00:00:00Z",
              "endDate": "2026-05-31T23:59:59Z",
              "groupBy": ["model"],
          }
      },
  )
  ```

  ```go Go theme={null}
  // By preset time range
  result, err := client.GetCreditUsage(context.Background(), stigg.CreditUsageInput{
    CustomerID: "customer-demo-01",
    CurrencyID: Ptr("ai-tokens"),
    TimeRange:  Ptr(stigg.CreditUsageTimeRangeLastMonth),
    ResourceID: Ptr("workspace-example-com"), // optional
  })

  // By exact date range with dimension breakdown
  start := time.Date(2026, 5, 1, 0, 0, 0, 0, time.UTC)
  end := time.Date(2026, 5, 31, 23, 59, 59, 0, time.UTC)
  result, err := client.GetCreditUsage(context.Background(), stigg.CreditUsageInput{
    CustomerID: "customer-demo-01",
    StartDate:  Ptr(start),
    EndDate:    Ptr(end),
    GroupBy:    []string{"model"},
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Query::CreditUsage, {
    "input": {
      "customerId": "customer-demo-01",
      "currencyId": "ai-tokens",
      "timeRange": "LAST_MONTH",
      "resourceId": "workspace-example-com",  # optional
      # OR use exact dates:
      # "startDate": "2026-05-01T00:00:00Z",
      # "endDate": "2026-05-31T23:59:59Z",
      # "groupBy": ["model"]
    }
  })
  ```

  ```java Java theme={null}
  var resp = stigg.query(
    CreditUsageQuery.builder()
    .input(
      CreditUsageInput.builder()
      .customerId("customer-demo-01")
      .currencyId("ai-tokens")
      .timeRange(CreditUsageTimeRange.LAST_MONTH)
      .resourceId("workspace-example-com") // optional
      // OR exact range:
      // .startDate(Instant.parse("2026-05-01T00:00:00Z"))
      // .endDate(Instant.parse("2026-05-31T23:59:59Z"))
      // .groupBy(List.of("model"))
      .build())
    .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.GetCreditUsage.ExecuteAsync(new CreditUsageInput()
  {
    CustomerId = "customer-demo-01",
    CurrencyId = "ai-tokens",
    TimeRange = CreditUsageTimeRange.LastMonth,
    ResourceId = "workspace-example-com", // optional
    // OR exact range:
    // StartDate = DateTime.Parse("2026-05-01"),
    // EndDate = DateTime.Parse("2026-05-31"),
    // GroupBy = new List<string> { "model" }
  });
  ```
</CodeGroup>

<Expandable title="Response (Node.js)">
  ```json theme={null}
  {
    "series": [
      {
        "featureId": "feature-ai-tokens",
        "featureName": "AI Tokens",
        "totalCredits": 8420,
        "points": [
          { "timestamp": "2026-05-01T00:00:00Z", "value": 350 },
          { "timestamp": "2026-05-02T00:00:00Z", "value": 480 }
        ]
      }
    ],
    "currency": { "currencyId": "ai-tokens", "displayName": "AI Tokens" },
    "pageInfo": { "hasNextPage": false, "hasPreviousPage": false }
  }
  ```
</Expandable>

When `groupBy` is set, each series entry includes a `tags` array instead of `featureId`/`featureName`:

```json theme={null}
{
  "series": [
    {
      "featureId": null,
      "featureName": null,
      "totalCredits": 16922285,
      "tags": [{ "key": "model", "value": "gemini" }],
      "points": [...]
    }
  ]
}
```

### Query credit ledger

Retrieve the append-only ledger of all credit events for a customer — grants, deductions, expirations, and revocations in chronological order. Pass `resourceId` to scope to a resource-specific pool.

<CodeGroup>
  ```javascript Node.js theme={null}
  const ledger = await stiggClient.getCreditLedger({
    customerId: 'customer-demo-01',
    currencyId: 'ai-tokens',              // optional
    resourceId: 'workspace-example-com', // optional
    paging: { first: 50 },              // optional
  });
  ```

  ```python Python theme={null}
  from stigg.types import CreditLedgerQuery

  result = await client.query(
      CreditLedgerQuery,
      {
          "input": {
              "customerId": "customer-demo-01",
              "currencyId": "ai-tokens",              # optional
              "resourceId": "workspace-example-com",  # optional
              "paging": {"first": 50},                # optional
          }
      },
  )
  ```

  ```go Go theme={null}
  result, err := client.GetCreditLedger(context.Background(), stigg.CreditLedgerInput{
    CustomerID: "customer-demo-01",
    CurrencyID: Ptr("ai-tokens"),
    ResourceID: Ptr("workspace-example-com"), // optional
    Paging:     &stigg.CursorPaging{First: Ptr(int64(50))},
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Query::CreditsLedger, {
    "input": {
      "customerId": "customer-demo-01",
      "currencyId": "ai-tokens",              # optional
      "resourceId": "workspace-example-com",  # optional
      "paging": { "first": 50 }
    }
  })
  ```

  ```java Java theme={null}
  var resp = stigg.query(
    CreditsLedgerQuery.builder()
    .input(
      CreditLedgerInput.builder()
      .customerId("customer-demo-01")
      .currencyId("ai-tokens")
      .resourceId("workspace-example-com") // optional
      .paging(CursorPaging.builder().first(50).build())
      .build())
    .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.GetCreditsLedger.ExecuteAsync(new CreditLedgerInput()
  {
    CustomerId = "customer-demo-01",
    CurrencyId = "ai-tokens",
    ResourceId = "workspace-example-com", // optional
    Paging = new CursorPaging() { First = 50 }
  });
  ```
</CodeGroup>

### Query credit grants

List all credit grants for a customer, with optional filtering by resource and currency.

<CodeGroup>
  ```javascript Node.js theme={null}
  const grants = await stiggClient.getCreditGrants({
    customerId: 'customer-demo-01',
    currencyId: 'ai-tokens',              // optional
    resourceId: 'workspace-example-com', // optional
    paging: { first: 20 },              // optional
  });
  ```

  ```python Python theme={null}
  from stigg.types import CreditGrantsQuery

  result = await client.query(
      CreditGrantsQuery,
      {
          "input": {
              "customerId": "customer-demo-01",
              "currencyId": "ai-tokens",             # optional
              "resourceId": "workspace-example-com", # optional
          }
      },
  )
  ```

  ```go Go theme={null}
  result, err := client.GetCreditGrants(context.Background(), stigg.GetCreditGrantsInput{
    CustomerID: "customer-demo-01",
    CurrencyID: Ptr("ai-tokens"),
    ResourceID: Ptr("workspace-example-com"), // optional
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Query::CreditGrants, {
    "input": {
      "customerId": "customer-demo-01",
      "currencyId": "ai-tokens",
      "resourceId": "workspace-example-com",  # optional
    }
  })
  ```

  ```java Java theme={null}
  var resp = stigg.query(
    CreditGrantsQuery.builder()
    .input(
      GetCreditGrantsInput.builder()
      .customerId("customer-demo-01")
      .currencyId("ai-tokens")
      .resourceId("workspace-example-com") // optional
      .build())
    .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.GetCreditGrants.ExecuteAsync(new GetCreditGrantsInput()
  {
    CustomerId = "customer-demo-01",
    CurrencyId = "ai-tokens",
    ResourceId = "workspace-example-com", // optional
  });
  ```
</CodeGroup>

### List available dimension keys

Retrieve the dimension keys that exist on a customer's credit usage events. Use `search` to filter by keyword. This powers the searchable **Group by** dropdown in analytics UIs.

<CodeGroup>
  ```javascript Node.js theme={null}
  const fields = await stiggClient.getCreditEventsFields({
    customerId: 'customer-demo-01',
    currencyId: 'ai-tokens', // optional
    search: 'model',         // optional — filter keys by substring
  });
  // → { fields: ['model', 'model_version'] }
  ```

  ```python Python theme={null}
  from stigg.types import CreditEventsFieldsQuery

  result = await client.query(
      CreditEventsFieldsQuery,
      {
          "input": {
              "customerId": "customer-demo-01",
              "currencyId": "ai-tokens",  # optional
              "search": "model",          # optional
          }
      },
  )
  ```

  ```go Go theme={null}
  result, err := client.GetCreditEventsFields(context.Background(), stigg.CreditEventsFieldsInput{
    CustomerID: "customer-demo-01",
    CurrencyID: Ptr("ai-tokens"),
    Search:     Ptr("model"),
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Query::CreditEventsFields, {
    "input": {
      "customerId": "customer-demo-01",
      "currencyId": "ai-tokens",  # optional
      "search": "model",          # optional
    }
  })
  ```

  ```java Java theme={null}
  var resp = stigg.query(
    CreditEventsFieldsQuery.builder()
    .input(
      CreditEventsFieldsInput.builder()
      .customerId("customer-demo-01")
      .currencyId("ai-tokens")
      .search("model")
      .build())
    .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.GetCreditEventsFields.ExecuteAsync(new CreditEventsFieldsInput()
  {
    CustomerId = "customer-demo-01",
    CurrencyId = "ai-tokens",
    Search = "model",
  });
  ```
</CodeGroup>

## Credit auto-recharge

Configure automatic credit recharge for customers. When a customer's credit balance drops below `thresholdValue`, Stigg automatically tops up to `targetBalance`. Set `isEnabled: false` to disable recharge without losing the configuration.

<CodeGroup>
  ```javascript Node.js theme={null}
  await stiggClient.saveAutoRechargeSettings({
    customerId: 'customer-demo-01',
    currencyId: 'ai-tokens',
    isEnabled: true,
    thresholdType: 'CREDIT_AMOUNT',  // CREDIT_AMOUNT | DOLLAR_AMOUNT
    thresholdValue: 500,             // trigger when balance drops below this
    targetBalance: 5000,             // top up to this amount
    maxSpendLimit: 100,              // optional — monthly USD spend cap
    grantExpirationPeriod: 'MONTH',  // optional — expiry for auto-granted credits
  });
  ```

  ```python Python theme={null}
  from stigg.types import SaveAutoRechargeSettingsMutation

  result = await client.mutation(
      SaveAutoRechargeSettingsMutation,
      {
          "input": {
              "customerId": "customer-demo-01",
              "currencyId": "ai-tokens",
              "isEnabled": True,
              "thresholdType": "CREDIT_AMOUNT",
              "thresholdValue": 500,
              "targetBalance": 5000,
              "maxSpendLimit": 100,         # optional
              "grantExpirationPeriod": "MONTH",  # optional
          }
      },
  )
  ```

  ```go Go theme={null}
  result, err := client.SaveAutoRechargeSettings(context.Background(), stigg.SaveAutoRechargeSettingsInput{
    CustomerID:            "customer-demo-01",
    CurrencyID:            "ai-tokens",
    IsEnabled:             true,
    ThresholdType:         Ptr(stigg.ThresholdTypeCreditAmount),
    ThresholdValue:        Ptr(float64(500)),
    TargetBalance:         Ptr(float64(5000)),
    MaxSpendLimit:         Ptr(float64(100)),             // optional
    GrantExpirationPeriod: Ptr(stigg.GrantExpirationPeriodMonth), // optional
  })
  ```

  ```ruby Ruby theme={null}
  resp = client.request(Stigg::Mutation::SaveAutoRechargeSettings, {
    "input": {
      "customerId": "customer-demo-01",
      "currencyId": "ai-tokens",
      "isEnabled": true,
      "thresholdType": "CREDIT_AMOUNT",
      "thresholdValue": 500,
      "targetBalance": 5000,
      "maxSpendLimit": 100,               # optional
      "grantExpirationPeriod": "MONTH",   # optional
    }
  })
  ```

  ```java Java theme={null}
  var resp = stigg.mutation(
    SaveAutoRechargeSettingsMutation.builder()
    .input(
      SaveAutoRechargeSettingsInput.builder()
      .customerId("customer-demo-01")
      .currencyId("ai-tokens")
      .isEnabled(true)
      .thresholdType(ThresholdType.CREDIT_AMOUNT)
      .thresholdValue(500.0)
      .targetBalance(5000.0)
      .maxSpendLimit(100.0)                       // optional
      .grantExpirationPeriod(GrantExpirationPeriod.MONTH) // optional
      .build())
    .build());
  ```

  ```c# .NET theme={null}
  var resp = await stigg.SaveAutoRechargeSettings.ExecuteAsync(new SaveAutoRechargeSettingsInput()
  {
    CustomerId = "customer-demo-01",
    CurrencyId = "ai-tokens",
    IsEnabled = true,
    ThresholdType = ThresholdType.CreditAmount,
    ThresholdValue = 500,
    TargetBalance = 5000,
    MaxSpendLimit = 100,                           // optional
    GrantExpirationPeriod = GrantExpirationPeriod.Month, // optional
  });
  ```
</CodeGroup>

<Card title="Auto-recharge overview" icon="bolt" horizontal href="/documentation/modeling-your-pricing-in-stigg/credits/auto-recharge/overview" />
