---
title: codespar_ship
description: Quote, label or track a shipment. Brazilian domestic shipping on Melhor Envio (Correios and private carriers) behind a neutral origin, destination and items shape; the router picks the cheapest carrier per request.
---

import { Callout } from "fumadocs-ui/components/callout";
import { Tabs, Tab } from "fumadocs-ui/components/tabs";

<MetaToolHeader tool="codespar_ship" />

The agent passes a neutral `{ origin, destination, items }` shape and never learns the carrier API; `action` picks quote, label or track.

## Actions

<MetaToolActions tool="codespar_ship" />

## Example

`action: "quote"`: carriers and prices for a parcel, with no label generated.

<Split min={380}>
<SplitPane label="The same call, four ways">

<Tabs items={["MCP", "TypeScript", "Python", "CLI"]}>
<Tab value="MCP">

```json title="arguments"
{
  "name": "codespar_ship",
  "arguments": {
    "action": "quote",
    "origin": {
      "postal_code": "00000000",
      "city": "Example",
      "state": "SP"
    },
    "destination": {
      "postal_code": "00000000",
      "city": "Example",
      "state": "RJ"
    },
    "items": [
      {
        "weight_g": 500,
        "dimensions": {
          "length_cm": 20,
          "width_cm": 15,
          "height_cm": 5
        }
      }
    ],
    "service_level": "cheapest"
  }
}
```

</Tab>
<Tab value="TypeScript">

```ts
const result = await session.execute("codespar_ship", {
  action: "quote",
  origin: {
    postal_code: "00000000",
    city: "Example",
    state: "SP"
  },
  destination: {
    postal_code: "00000000",
    city: "Example",
    state: "RJ"
  },
  items: [
    {
      weight_g: 500,
      dimensions: {
        length_cm: 20,
        width_cm: 15,
        height_cm: 5
      }
    }
  ],
  service_level: "cheapest"
});
```

</Tab>
<Tab value="Python">

```python
result = session.execute("codespar_ship", {
  "action": "quote",
  "origin": {
    "postal_code": "00000000",
    "city": "Example",
    "state": "SP"
  },
  "destination": {
    "postal_code": "00000000",
    "city": "Example",
    "state": "RJ"
  },
  "items": [
    {
      "weight_g": 500,
      "dimensions": {
        "length_cm": 20,
        "width_cm": 15,
        "height_cm": 5
      }
    }
  ],
  "service_level": "cheapest"
})
```

</Tab>
<Tab value="CLI">

```bash
codespar tool codespar_ship \
  -i '{
       "action": "quote",
       "origin": {
         "postal_code": "00000000",
         "city": "Example",
         "state": "SP"
       },
       "destination": {
         "postal_code": "00000000",
         "city": "Example",
         "state": "RJ"
       },
       "items": [
         {
           "weight_g": 500,
           "dimensions": {
             "length_cm": 20,
             "width_cm": 15,
             "height_cm": 5
           }
         }
       ],
       "service_level": "cheapest"
     }'
```

</Tab>
</Tabs>

</SplitPane>
<SplitPane label="Result">

Result shape: see runtime. The tool document names no result field for any action (the earlier page documented `quotes[]`, `tracking_code`, `label_url` and `events[]`; see Notes). The published document is [`/v1/meta-tools.json`](https://api.codespar.dev/v1/meta-tools.json).

</SplitPane>
</Split>

## When to use

- **Quote first, then label.** `quote` needs no carrier balance; `label` generates a paid label and needs the operator's Melhor Envio wallet funded.
- **Tracking**: `track` with the `tracking_code` a label returned, for the shipping update [`codespar_notify`](/docs/concepts/meta-tools/notify) sends.
- **In the sell-side chain**: charge → wait for settlement → invoice → ship → notify. The [Webhook Listener cookbook](/docs/cookbooks/webhook-listener) generates the label on settlement.

## Arguments

| Field | Type | Required | Description |
|---|---|---|---|
| `action` | `string` | Yes | `"label"` \| `"quote"` \| `"track"`. There is no default: a missing or unknown value is refused (measured 2026-09-09) |
| `origin` | `object` | For `label`, `quote` | Sender address (`postal_code` + `city` + `state`) |
| `destination` | `object` | For `label`, `quote` | Recipient address, same shape |
| `items` | `array` | For `label`, `quote` | Items to ship, each with `weight_g` and `dimensions` |
| `service_level` | `string` | No | `fastest` \| `cheapest` \| `standard` |
| `tracking_code` | `string` | For `track` | The carrier tracking code a label returned |
| `metadata` | `object` | No | Provider-specific overrides |

## Errors and what to do

| Error | Cause | What to do |
|---|---|---|
| `invalid_args` | `action` missing or outside `label` / `track` / `quote` (the message says so); `origin`, `destination` or a non-empty `items` missing on `label` / `quote`. Nothing is dispatched. | Fix the call against the Arguments table. |
| `no_eligible_providers` | Melhor Envio is not connected on this project. | Connect it (OAuth) via [`codespar_manage_connections`](/docs/concepts/meta-tools/manage-connections). |
| A `label` that fails with a funded quote | The operator's Melhor Envio wallet has no balance; quotes work without one. | Fund the carrier wallet, then retry the label. |

## Money and mandate

`label` buys a shipping label, charged to the operator's connected Melhor Envio account, so it can cost money; `quote` and `track` are reads. No consumer wallet or mandate is involved: this is a sell-side, operator-funded tool.

## Related

- [`codespar_notify`](/docs/concepts/meta-tools/notify): the shipping update with the tracking code
- [`codespar_invoice`](/docs/concepts/meta-tools/invoice): the fiscal document that travels with the parcel
- [SDK reference](/docs/api/sdk/money#ship): `session.ship()`
- [E-Commerce Checkout cookbook](/docs/cookbooks/ecommerce-checkout): quote and label as part of fulfillment
- [Webhook Listener cookbook](/docs/cookbooks/webhook-listener): label generation on settlement

## Notes

**Rails, as previously documented.** All three actions run on Melhor Envio, exposed as three catalog rails (`domestic-label`, `domestic-quote`, `domestic-track`) so the agent picks the intent without learning the carrier API; the quote spans Correios, Jadlog, Loggi and others. International carriers are described by the tool document as reachable "via a unified shape"; the earlier page listed no line for them and this revision did not verify one.

**Operator setup.** Melhor Envio connects by OAuth: the operator clicks Connect in `/dashboard/auth-configs`, authorizes at Melhor Envio, and picks the warehouse account; sandbox vs production toggle in the modal. The Melhor Envio wallet must be funded before `label` calls succeed.

**Result shapes (SDK), as previously documented.** `quote`: `{ quotes: Array<{ carrier, service_id, service_name, price_minor, estimated_days }> }`; `label`: `{ tracking_code, label_url (PDF), carrier, service_name, cost_minor }`; `track`: `{ tracking_code, carrier, status: "in_transit" | "out_for_delivery" | "delivered" | "exception", events: Array<{ timestamp, description, location? }> }`. This revision did not re-verify these lists against the runtime.

**From the SDK.** `session.ship(args)` is the typed wrapper; `session.execute("codespar_ship", arguments)` takes the same arguments as the MCP call. An earlier version of this page wrote items as `{ weight_grams, length_cm, width_cm, height_cm }`; the schema says each item carries `weight_g` and `dimensions`.
