---
title: Marketplace Payout
description: Split a marketplace transaction into platform fee + seller payout. One agent, two settled transactions, full audit trail.
---

<ActionBar githubPath="content/docs/cookbooks/marketplace-payout.mdx" markdownPath="/api/docs-md/cookbooks/marketplace-payout" />

<MetaStrip items={[
  { label: "TIME", value: "~15 min" },
  { label: "PROVIDER", value: (<><ServerChip name="Claude" accent /><span style={{ color: "var(--color-fd-muted-foreground)", fontSize: 12 }}>opus-4-6</span></>) },
  { label: "SERVERS", value: (<><ServerChip name="stripe" /><ServerChip name="stark-bank" /><ServerChip name="nuvem-fiscal" /></>) },
]} />

A marketplace collects a charge from the buyer, keeps its platform fee, and pays the seller the remainder. Two settled transactions (one charge + one payout) — $0.20 total, everything else included. The agent handles the whole flow: capture, reconcile, payout, invoice.

## The money flow

| Step | Meta-tool | Direction | Billed |
|------|-----------|-----------|--------|
| 1. Charge buyer (R$1,000) | `codespar_pay` (card via Stripe) | Buyer → Platform | 1 tx ($0.10) |
| 2. Calculate split (platform fee 15%) | — | — | (logic, not billed) |
| 3. Payout seller (R$850 via Pix) | `codespar_pay` (payout via Stark Bank) | Platform → Seller | 1 tx ($0.10) |
| 4. Issue NF-e for platform fee (R$150) | `codespar_invoice` | — | included in charge tx |

Total: 2 transactions × $0.10 = $0.20, regardless of how many providers the flow touches.

## Prerequisites

```bash
npm install @codespar/sdk @codespar/claude @anthropic-ai/sdk
```

<Callout>
You need the merchant's own Stripe account + a Stark Bank account with outbound Pix enabled. See [Authentication > Connect Links](/docs/concepts/authentication) for user-level OAuth.
</Callout>

## Full agent code

```typescript title="marketplace-payout.ts"
import Anthropic from "@anthropic-ai/sdk";
import { CodeSpar } from "@codespar/sdk";
import { getTools, handleToolUse, toToolResultBlock } from "@codespar/claude";

const claude = new Anthropic();
const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });

interface Order {
  order_id: string;
  buyer: { email: string; card_token: string };
  seller: { id: string; bank_pix_key: string; cnpj: string };
  gross_amount: number; // centavos, e.g. 100000 = R$1,000
  platform_fee_bps: number; // basis points, e.g. 1500 = 15%
}

async function marketplacePayout(order: Order) {
  const session = await codespar.create(order.seller.id, {
    servers: ["stripe", "stark-bank", "nuvem-fiscal"],
    metadata: {
      order_id: order.order_id,
      marketplace_flow: "payout_v1",
    },
  });

  try {
    const tools = await getTools(session);
    const platformFee = Math.round(order.gross_amount * order.platform_fee_bps / 10000);
    const payoutAmount = order.gross_amount - platformFee;

    const messages: Anthropic.MessageParam[] = [
      {
        role: "user",
        content: `
Execute a marketplace order settlement:

1. Charge R$${(order.gross_amount / 100).toFixed(2)} on the buyer card (token: ${order.buyer.card_token}) via Stripe.
2. Once the charge settles, pay out R$${(payoutAmount / 100).toFixed(2)} via Pix to the seller key ${order.seller.bank_pix_key} via Stark Bank.
3. Issue an NF-e for the platform fee R$${(platformFee / 100).toFixed(2)} to seller CNPJ ${order.seller.cnpj} via Nuvem Fiscal.
4. Return the charge_id, payout_id, and nfe_access_key.

Stop immediately if the charge fails — do not attempt payout or invoice.
        `,
      },
    ];

    let response = await claude.messages.create({
      model: "claude-opus-4-6",
      max_tokens: 4096,
      tools,
      messages,
    });

    let iterations = 0;
    while (response.stop_reason === "tool_use" && iterations < 10) {
      const blocks = response.content.filter(
        (b): b is Anthropic.ToolUseBlock => b.type === "tool_use",
      );
      const results = await Promise.all(
        blocks.map(async (block) => {
          const out = await handleToolUse(session, block);
          return toToolResultBlock(block.id, out);
        }),
      );
      messages.push({ role: "assistant", content: response.content });
      messages.push({ role: "user", content: results });
      response = await claude.messages.create({
        model: "claude-opus-4-6",
        max_tokens: 4096,
        tools,
        messages,
      });
      iterations++;
    }

    const final = response.content.find(
      (b): b is Anthropic.TextBlock => b.type === "text",
    );
    return final?.text ?? "";
  } finally {
    await session.close();
  }
}
```

## Deterministic mode

If the flow never branches and you do not need LLM reasoning mid-run, swap the Claude loop for `session.loop()`. Faster, cheaper, easier to debug:

```typescript
const result = await session.loop({
  steps: [
    {
      tool: "codespar_pay",
      params: { method: "card", amount: order.gross_amount, card_token: order.buyer.card_token },
    },
    {
      tool: "codespar_pay",
      params: (prev) => ({
        action: "payout",
        method: "pix",
        amount: order.gross_amount - platformFee,
        pix_key: order.seller.bank_pix_key,
        source_payment_id: prev[0].data.payment_id,
      }),
    },
    {
      tool: "codespar_invoice",
      params: (prev) => ({
        type: "nfe",
        amount: platformFee,
        customer: { cnpj: order.seller.cnpj },
        reference: prev[0].data.payment_id,
      }),
    },
  ],
  abortOnError: true, // stop if the charge fails
});
```

## Variations

### Escrow / milestone release
Hold the charge in an escrow account until the seller fulfills the order. Pay out only after a shipping-confirmed event. Use the managed [escrow feature](/docs/concepts/billing) on the Orchestration tier — your agent calls a single `codespar_pay` with `escrow: true` and releases it with a follow-up call after the fulfillment webhook.

### Split across multiple sellers
For a multi-vendor cart (N sellers per order), turn the payout step into a loop:

```typescript
steps: [
  { tool: "codespar_pay", params: { method: "card", amount: order.gross } },
  ...order.sellers.map((seller) => ({
    tool: "codespar_pay",
    params: { action: "payout", method: "pix", amount: seller.share, pix_key: seller.pix },
  })),
]
```

Each payout is one settled transaction.

## Next steps

<NextStepsGrid items={[
  { label: "COOKBOOK", title: "Bulk Refund", description: "Refund N payments in parallel — dispute handling and chargeback flows.", href: "/docs/cookbooks/bulk-refund" },
  { label: "COOKBOOK", title: "Multi-Tenant Agent", description: "One marketplace, many seller tenants — session isolation per seller.", href: "/docs/cookbooks/multi-tenant" },
  { label: "CONCEPT", title: "Billing", description: "How platform fees, payouts, and NF-e map to settled transactions.", href: "/docs/concepts/billing" },
  { label: "CONCEPT", title: "Tools & Meta-Tools", description: "codespar_pay action: charge vs payout vs refund.", href: "/docs/concepts/tools" },
]} />
