Skip to main content
Glama

update_product_rate_plan_charge

Update a product rate plan charge by sending only the fields to change; the tool merges them with the current charge and validates before updating.

Instructions

Update a product rate plan charge. PUT /product-rateplan-charges/{chargeId}. You can send only the fields you want to change (e.g. chargeTier with new price); the tool fetches the current charge and merges your input so the backend receives all required fields. Validates in MCP before calling the API. Optional inputs: name, chargeType, chargeModel, billCycleType, category, chargeTier (currency, price as dollars e.g. 22.87 or cents e.g. 2287), taxable, weight, endDateCondition, billingPeriod, billingTiming, billingPeriodAlignment, specificBillingPeriod, billCycleDay (1-31 when billCycleType specificDayOfMonth), weeklyBillCycleDay (when specificDayOfWeek), monthlyBillCycleYear (1-12 when specificMonthOfYear). When chargeType is recurring, billingPeriod, specificBillingPeriod, billingPeriodAlignment, billingTiming are required.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
chargeIdYesProduct rate plan charge ID (required)
nameNoCharge name
chargeTypeNooneTime, recurring, or usage
chargeModelNoflatFeePricing, perUnitPricing, tieredPricing, or volumePricing
billCycleTypeNochargeTriggerDay, defaultFromCustomer, specificDayOfMonth, specificDayOfWeek, specificMonthOfYear, subscriptionStartDay, subscriptionFreeTrial
categoryNophysical or digital
chargeTierNoArray of {currency, price (dollars e.g. 22.87 or cents e.g. 2287), optional startingUnit, endingUnit, priceFormat, tier}. To update only price, send this and chargeId; other fields are filled from current charge.
taxableNoWhether taxable
weightNoWeight (integer)
descriptionNoDescription
endDateConditionNosubscriptionEnd or fixedPeriod
billingPeriodNoday, week, month, or year (required if chargeType recurring)
billingTimingNoinAdvance or inArrears (required if chargeType recurring)
billingPeriodAlignmentNoalignToCharge, alignToSubscriptionStart, alignToTermStart (required if chargeType recurring)
specificBillingPeriodNoRequired when chargeType recurring
billCycleDayNo1-31 when billCycleType is specificDayOfMonth
weeklyBillCycleDayNosunday, monday, tuesday, wednesday, thursday, friday, saturday when billCycleType is specificDayOfWeek
monthlyBillCycleYearNo1-12 when billCycleType is specificMonthOfYear

Implementation Reference

  • The main handler function for update_product_rate_plan_charge. Parses input with Zod schema, fetches existing charge via chargeService.getRatePlanCharge(), merges user-provided fields with existing data via existingChargeToUpdateBody(), validates the merged body with validateMergedBody(), then calls chargeService.updateRatePlanCharge() to PUT the update via the API.
    async function handler(client: Client, args: Record<string, unknown> | undefined) {
      const parsed = schema.safeParse(args);
      if (!parsed.success) {
        return errorResult(parsed.error.errors.map((e) => e.message).join("; "));
      }
      const input = parsed.data;
      const { chargeId, chargeTier: inputChargeTier, ...restInput } = input;
    
      try {
        // Fetch existing charge so we can merge when user sends partial update (e.g. only price)
        const existing = await chargeService.getRatePlanCharge(client, chargeId);
        const existingBody = chargeService.existingChargeToUpdateBody(existing);
    
        // User payload: only include fields the user actually provided (defined), so we don't overwrite with undefined
        const userPayload: Record<string, unknown> = {};
        for (const [k, v] of Object.entries(restInput)) {
          if (v !== undefined) userPayload[k] = v;
        }
        if (inputChargeTier !== undefined) {
          userPayload.chargeTier = inputChargeTier.map((t) => ({
            ...t,
            price: normalizePriceToCents(t.price),
            priceFormat: t.priceFormat ?? "",
          }));
        }
    
        const merged: UpdateRatePlanChargeBody = {
          ...existingBody,
          ...userPayload,
        } as UpdateRatePlanChargeBody;
    
        // Ensure chargeTier tiers have priceFormat for API
        if (merged.chargeTier?.length) {
          merged.chargeTier = merged.chargeTier.map((t) => ({
            ...t,
            priceFormat: t.priceFormat ?? "",
          }));
        }
    
        validateMergedBody(merged);
    
        return handleToolCall(() => chargeService.updateRatePlanCharge(client, chargeId, merged));
      } catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        return errorResult(message);
      }
    }
  • Zod input schema defining the tool's input validation. Only chargeId is required; all other fields (name, chargeType, chargeModel, billCycleType, category, chargeTier, taxable, weight, description, endDateCondition, billingPeriod, billingTiming, billingPeriodAlignment, specificBillingPeriod, billCycleDay, weeklyBillCycleDay, monthlyBillCycleYear) are optional for partial updates.
    const schema = z.object({
      chargeId: z.string().min(1, "chargeId is required"),
      name: z.string().min(1).optional(),
      chargeType: z.enum(chargeTypeEnum).optional(),
      chargeModel: z.enum(chargeModelEnum).optional(),
      billCycleType: z.enum(billCycleTypeEnum).optional(),
      category: z.enum(["physical", "digital"]).optional(),
      chargeTier: z.array(chargeTierItemSchema).optional(),
      taxable: z.boolean().optional(),
      weight: z.coerce.number().int().min(0).optional(),
      description: z.string().optional(),
      endDateCondition: z.enum(["subscriptionEnd", "fixedPeriod"]).optional(),
      billingPeriod: z.enum(billingPeriodEnum).optional(),
      billingTiming: z.enum(billingTimingEnum).optional(),
      billingPeriodAlignment: z.enum(billingPeriodAlignmentEnum).optional(),
      specificBillingPeriod: z.number().int().optional(),
      billCycleDay: z.number().int().min(1).max(31).optional(),
      weeklyBillCycleDay: z.enum(weeklyBillCycleDayEnum).optional(),
      monthlyBillCycleYear: z.number().int().min(1).max(12).optional(),
    });
  • Exports updateRatePlanChargeTool as a Tool object with the definition and handler.
    export const updateRatePlanChargeTool: Tool = {
      definition,
      handler,
    };
  • The executeTool function finds the tool by name and calls its handler. The tool is registered via registerProductRatePlanChargeTools() on line 30, which includes updateRatePlanChargeTool.
    export async function executeTool(
      name: string,
      args: Record<string, unknown> | undefined,
      client: RebilliaClient
    ): Promise<ToolResult | undefined> {
      const tool = tools.find((t) => t.definition.name === name);
      if (!tool) return undefined;
      return tool.handler(client, args);
    }
  • The updateRatePlanCharge API service function that performs the actual PUT /product-rateplan-charges/{chargeId} HTTP call, filtering out undefined values and normalizing charge tiers before sending.
    export async function updateRatePlanCharge(
      client: Client,
      chargeId: string,
      body: UpdateRatePlanChargeBody
    ): Promise<unknown> {
      const payload = Object.fromEntries(
        Object.entries(body).filter(([, v]) => v !== undefined)
      ) as UpdateRatePlanChargeBody;
      if (payload.weight != null) payload.weight = Number(payload.weight);
      if (payload.chargeTier?.length) payload.chargeTier = normalizeChargeTier(payload.chargeTier);
      return client.put<unknown>(
        `/product-rateplan-charges/${chargeId}`,
        Object.keys(payload).length ? payload : undefined
      );
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses important behaviors: fetches current charge, merges input, validates before API call. However, no annotations are present, so description carries full burden. Missing details on permissions, atomicity, reversibility, or error handling. Moderately transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single paragraph but efficiently conveys purpose, merge behavior, validation, and lists optional inputs with conditions. Front-loaded with action. Could be more structured (e.g., bullet points) but is concise enough.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, so description should explain return values. It covers merge logic, validation, and field conditions, but does not describe the response format or error scenarios. For a complex tool with 18 parameters, it's fairly complete but missing output info.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, baseline 3. Description adds value by explaining the merge behavior for chargeTier (only send fields to change) and conditional requirements (e.g., when chargeType is recurring, billingPeriod required). This extra context goes beyond schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states 'Update a product rate plan charge' and mentions the HTTP endpoint. However, it does not explicitly differentiate from the sibling tool 'create_product_rate_plan_charge', which could cause confusion. The purpose is clear but not fully distinguished.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Describes the merge behavior and validation, implying when to use (partial updates). But it does not explicitly state when not to use (e.g., use create for new charges) or mention alternatives. Some guidance but lacks explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rhinosaas/rebillia-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server