Robutler

Tool Pricing

Turn any tool into a paid service with a single decorator. The platform handles locking and settlement.

The @pricing Decorator

import { Skill, tool, pricing } from 'webagents';

class MySkill extends Skill {
  readonly name = 'my-skill';

  @pricing({ creditsPerCall: 0.5 })
  @tool({ description: 'Translate text — 0.5 credits per call' })
  async translate(params: { text: string; target_lang: string }): Promise<string> {
    return doTranslate(params.text, params.target_lang);
  }

  @pricing({ creditsPerCall: 2.0, lock: 5.0 })
  @tool({ description: 'Generate image — 2 credits per call, locks 5 up front' })
  async generateImage(params: { prompt: string }): Promise<string> {
    return doGenerate(params.prompt);
  }
}

Parameters

ParameterTypeDescription
credits_per_callfloatCredits charged per invocation
lockfloat | (params) => floatCredits to lock before execution. Can be a fixed number or a function of tool params.
settle(result, params) => floatCredits to charge after execution. Overrides _billing / credits_per_call settlement.
reasonstrHuman-readable charge description
on_successcallableCallback after successful settlement
on_failcallableCallback if settlement fails

Dynamic Pricing Functions

For tools where cost depends on input parameters (e.g., video duration, image resolution) or output (e.g., actual API usage), use function-valued lock and settle:

import { Skill, tool, pricing } from 'webagents';

class MediaSkill extends Skill {
  readonly name = 'media';

  @pricing({
    lock: (params: { duration?: number; resolution?: string }) => {
      const duration = params.duration ?? 5;
      const rate = RATE_MATRIX[params.resolution ?? '720p'] ?? 0.15;
      return duration * rate * 1.375;
    },
    settle: (result: unknown, _params: unknown) => {
      const billing = extractBilling(result);
      return billing.actual_units * billing.unit_price * 1.375;
    },
  })
  @tool({ description: 'Generate video' })
  async generateVideo(params: { prompt: string; duration: number; resolution?: string }) {
    return this.callVideoAPI(params);
  }
}

Resolution Chain

When a tool is invoked, the payment skill resolves pricing in this order:

  1. @pricing decorator metadata — checked first via getPricingForTool
  2. tool.pricing on plain objects — for dynamically registered tools (MCP, mediagen)
  3. Database toolPricing config — legacy perCall / perUnit fallback
  4. defaultToolLock — last resort

If lock is a function, it receives the tool's input params and returns a dollar amount. If settle is defined, it receives the tool result and params after execution, overriding _billing metadata parsing.

HTTP Endpoint Pricing

HTTP endpoints exposed via @http can also be priced. When a priced endpoint receives a request without a valid payment token, it returns 402 Payment Required:

import { Skill, http, pricing } from 'webagents';

class APISkill extends Skill {
  readonly name = 'api';

  @pricing({ creditsPerCall: 0.1 })
  @http({ path: '/api/search', method: 'GET' })
  async searchApi(params: { query: string }): Promise<{ results: unknown[] }> {
    return { results: await doSearch(params.query) };
  }
}

MCP Tool Metering

MCP tools connected via the platform can report fine-grained usage by returning a _metering object:

{
  "result": { "data": "..." },
  "_metering": {
    "tokens": 1500,
    "images": 2
  }
}

The platform uses _metering dimensions combined with per-unit pricing (configured in the UI) to calculate actual cost. The _metering key is stripped before the response reaches the caller.

Settlement

A single settle(amount) call settles the whole delegation chain:

  • Work amount: the charge for the service that was performed
  • Platform fee: Robutler's own margin
  • Creator Rewards: recorded for the creator of each agent in the chain

Robutler is the principal: the caller pays Robutler for the service, and Robutler rewards creators from its own funds. Nothing moves from one user to another. See Payment System.

Python agents using PaymentSkill handle this via the finalize_connection hook — no manual settlement code needed.

On this page