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

# Agent SDK

> Instrument an AI agent in a few lines of Python or TypeScript — route LLM calls through the proxy, report outcomes, and bill on results.

The Agent SDK is the drop-in instrumentation layer for agent billing: point your existing OpenAI client at the Macropay proxy to capture model cost automatically, then report what the agent did and achieved so margin and ROI compute themselves. It ships for both **Python** (`macropay`) and **TypeScript** (`@macropay/sdk`) with a matching API.

<Info>
  Instrumentation does three things: **captures LLM cost** (via the proxy base URL), **reports signals** (activity + outcome), and **records non-LLM cost** (tools, third-party APIs, human-in-the-loop). Those three feeds power [Agentic Margin](/features/agents/margin) and [value receipts](/features/agents/value-receipts).
</Info>

## Install

<CodeGroup>
  ```bash Python theme={null}
  pip install macropay
  ```

  ```bash TypeScript theme={null}
  npm install @macropay/sdk openai
  ```
</CodeGroup>

## Capture LLM cost with one base URL

The Macropay AI proxy is OpenAI-compatible and mounted at `/ai/v1`. Point any OpenAI client at it, authenticate with an **agent-bound proxy key**, and every call's cost is attributed to that agent — no wrapper code. The SDK exposes a helper so you never hand-write the URL.

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI
  from macropay.agents import openai_base_url

  oai = OpenAI(
      api_key="macropay_proxy_...",          # agent-bound proxy key
      base_url=openai_base_url(),            # https://api.macropay.ai/ai/v1
  )
  ```

  ```ts TypeScript theme={null}
  import OpenAI from "openai";
  import { openaiBaseUrl } from "@macropay/sdk";

  const oai = new OpenAI({
    apiKey: "macropay_proxy_...",            // agent-bound proxy key
    baseURL: openaiBaseUrl(),                // https://api.macropay.ai/ai/v1
  });
  ```
</CodeGroup>

`openai_base_url()` / `openaiBaseUrl()` default to production. Pass `sandbox=True` (Python) or `{ sandbox: true }` (TypeScript) to target the sandbox, or pass an explicit base URL to override. See [LLM inference](/features/llm-inference) for the full proxy reference.

## AgentInstrumentation

`AgentInstrumentation` binds one agent (and optionally one customer) once, so every signal and cost call is a one-liner. It wraps the low-level Macropay client.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from macropay import Macropay
    from macropay.agents import AgentInstrumentation

    client = Macropay(api_key="macropay_sk_...")

    agent = AgentInstrumentation(
        client,
        agent_id="agt_sdr",
        customer_id="cus_123",             # or external_customer_id="acme-co"
    )
    ```

    | Method                                                                               | Purpose                                                                   |
    | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
    | `activity(event_name, data=None, external_id=None)`                                  | Report an action the agent took (`message_sent`, `tool_call`).            |
    | `outcome(event_name, value_cents=None, verified=False, data=None, external_id=None)` | Report a result (`meeting_booked`, `deal_won`). `value_cents` drives ROI. |
    | `record_cost(amount_cents, description=None, currency="usd", external_id=None)`      | Record non-LLM COGS so margin reflects true cost.                         |
    | `margin(**params)`                                                                   | Fetch this agent's current Agentic Margin.                                |
    | `value_receipt(**assumptions)`                                                       | Fetch this agent's ROI value receipt.                                     |
    | `track_tool(name, cost_cents=...)`                                                   | Async context manager — auto-records cost **on success only**.            |
    | `track_cost(name, cost_cents=...)`                                                   | Decorator — auto-records cost **on success only**.                        |

    All methods are `async`. Pass `external_id` to dedupe — outcomes are idempotent on it.
  </Tab>

  <Tab title="TypeScript">
    ```ts theme={null}
    import { Macropay, AgentInstrumentation } from "@macropay/sdk";

    const client = new Macropay({ apiKey: "macropay_sk_..." });

    const agent = new AgentInstrumentation(client, "agt_sdr", {
      customerId: "cus_123",               // or externalCustomerId: "acme-co"
    });
    ```

    | Method                                                           | Purpose                                                 |
    | ---------------------------------------------------------------- | ------------------------------------------------------- |
    | `activity(eventName, { data, externalId })`                      | Report an action the agent took.                        |
    | `outcome(eventName, { valueCents, verified, data, externalId })` | Report a result; `valueCents` drives ROI.               |
    | `recordCost(amountCents, { description, currency, externalId })` | Record non-LLM COGS.                                    |
    | `setupBilling({ kind, pricePerUnitCents, ... })`                 | Provision a meter + product for this agent in one call. |
    | `margin(params)`                                                 | Fetch this agent's current Agentic Margin.              |
    | `valueReceipt(params)`                                           | Fetch this agent's ROI value receipt.                   |

    All methods return promises. Pass `externalId` to dedupe — outcomes are idempotent on it.
  </Tab>
</Tabs>

## Report what the agent did and achieved

[Signals](/features/agents/signals) are the heart of agent billing. **Activity** signals are what the agent *did*; **outcome** signals are what it *achieved* — and an outcome carries the value it produced.

<CodeGroup>
  ```python Python theme={null}
  # Something the agent did
  await agent.activity("message_sent", data={"channel": "email"})

  # Something the agent achieved, worth $200, confirmed by your CRM
  await agent.outcome(
      "meeting_booked",
      value_cents=20000,
      verified=True,
      external_id="hubspot-deal-8841",       # idempotent dedupe key
  )
  ```

  ```ts TypeScript theme={null}
  // Something the agent did
  await agent.activity("message_sent", { data: { channel: "email" } });

  // Something the agent achieved, worth $200, confirmed by your CRM
  await agent.outcome("meeting_booked", {
    valueCents: 20000,
    verified: true,
    externalId: "hubspot-deal-8841",         // idempotent dedupe key
  });
  ```
</CodeGroup>

<Note>
  Set `verified` when an outcome is confirmed by a trusted source — a CRM webhook, a payment, a signed contract — rather than self-reported by the agent. The [value receipt](/features/agents/value-receipts) then splits **verified** from **unverified** value, exposing the trust gap to your customer.
</Note>

## Record non-LLM cost

LLM cost is captured automatically through the proxy. Everything else — search APIs, enrichment, human review — you report with `record_cost` so [margin](/features/agents/margin) reflects true COGS.

<CodeGroup>
  ```python Python theme={null}
  await agent.record_cost(50, description="serp_api")   # 50 cents
  ```

  ```ts TypeScript theme={null}
  await agent.recordCost(50, { description: "serp_api" }); // 50 cents
  ```
</CodeGroup>

### Automatic tool-cost capture (Python)

`track_tool` (an async context manager) and `track_cost` (a decorator) record the cost **and** emit a `tool.<name>` activity signal — but **only when the call succeeds**. A tool call that raises was a failure you weren't charged for, so it never touches margin.

```python theme={null}
# As a context manager
async with agent.track_tool("serp_search", cost_cents=2):
    results = await serp.search(query)

# As a decorator — cost_cents can be a number or a callable for usage pricing
@agent.track_cost("enrich", cost_cents=lambda rows: len(rows) * 1)
async def enrich(rows: list[dict]) -> list[dict]:
    ...
```

## End-to-end: route a call, post an outcome

A minimal SDR-style agent: the LLM call goes through the proxy (cost captured), then the booked meeting is reported as a verified outcome worth \$200.

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI
  from macropay import Macropay
  from macropay.agents import openai_base_url, AgentInstrumentation

  # 1. LLM client routed through the proxy → cost auto-attributed to the agent
  oai = OpenAI(api_key="macropay_proxy_...", base_url=openai_base_url())

  # 2. Instrumentation bound to the agent + customer
  client = Macropay(api_key="macropay_sk_...")
  agent = AgentInstrumentation(client, "agt_sdr", customer_id="cus_123")

  # 3. Do the work
  reply = oai.chat.completions.create(
      model="gpt-4o-mini",
      messages=[{"role": "user", "content": "Draft a meeting request for Acme."}],
  )
  await agent.activity("message_sent", data={"channel": "email"})

  # 4. Report the result — this is what you bill and prove ROI on
  await agent.outcome(
      "meeting_booked",
      value_cents=20000,
      verified=True,
      external_id="hubspot-deal-8841",
  )
  ```

  ```ts TypeScript theme={null}
  import OpenAI from "openai";
  import { Macropay, openaiBaseUrl, AgentInstrumentation } from "@macropay/sdk";

  // 1. LLM client routed through the proxy → cost auto-attributed to the agent
  const oai = new OpenAI({ apiKey: "macropay_proxy_...", baseURL: openaiBaseUrl() });

  // 2. Instrumentation bound to the agent + customer
  const client = new Macropay({ apiKey: "macropay_sk_..." });
  const agent = new AgentInstrumentation(client, "agt_sdr", { customerId: "cus_123" });

  // 3. Do the work
  const reply = await oai.chat.completions.create({
    model: "gpt-4o-mini",
    messages: [{ role: "user", content: "Draft a meeting request for Acme." }],
  });
  await agent.activity("message_sent", { data: { channel: "email" } });

  // 4. Report the result — this is what you bill and prove ROI on
  await agent.outcome("meeting_booked", {
    valueCents: 20000,
    verified: true,
    externalId: "hubspot-deal-8841",
  });
  ```
</CodeGroup>

## Close the billing loop in one call

`setup_billing` / `setupBilling` provisions a signal-scoped meter for the agent **and** a product with a `metered_unit` price — so you skip the manual meter to price to product wiring. Bill per activity or per outcome.

<CodeGroup>
  ```python Python theme={null}
  await agent.setup_billing(
      kind="outcome",
      signal_name="meeting_booked",
      price_per_unit_cents=500,              # $5 per booked meeting
      product_name="SDR — per meeting",
  )
  ```

  ```ts TypeScript theme={null}
  await agent.setupBilling({
    kind: "outcome",
    signalName: "meeting_booked",
    pricePerUnitCents: 500,                  // $5 per booked meeting
    productName: "SDR — per meeting",
  });
  ```
</CodeGroup>

<Tip>
  Outcome-based pricing pairs naturally with verified outcomes: charge only for results your CRM confirmed. See [outcome-based billing in practice](/guides/ai-billing) for the full pattern.
</Tip>

## FAQ

**Do I need the SDK?**
No. The SDK is a thin convenience layer over the REST API — you can route LLM calls through the [proxy](/features/llm-inference) and post [signals](/features/agents/signals) with plain HTTP. The SDK just makes cost capture, signal reporting, and billing setup one-liners in Python and TypeScript.

**How do I bill by outcome with the SDK?**
Report results with `outcome(event_name, value_cents=...)`, then create an outcome meter and price. `setup_billing(kind="outcome", signal_name=..., price_per_unit_cents=...)` does both in one call, so each reported outcome bills your customer automatically. Mark outcomes `verified` to bill only on results a trusted source confirmed.

**Which languages are supported?**
Python (the `macropay` package) and TypeScript (`@macropay/sdk`) have full parity for agent instrumentation. Both expose `openai_base_url` / `openaiBaseUrl` and `AgentInstrumentation`. Any other language can use the [REST API](/api-reference) directly.

**Does the proxy add latency?**
The proxy forwards your request to the upstream provider and streams the response back; metering happens on the response, not in the critical path. You also get real-time usage and budget headers on every call — see [LLM inference](/features/llm-inference).

**How is the LLM cost attributed to the right agent?**
Through the proxy key. Mint a proxy key bound to the agent, set it as the OpenAI client's `api_key`, and every call through `openai_base_url()` records its token cost against that agent — feeding [Agentic Margin](/features/agents/margin) with zero extra code.
