Talk to an Odoo ERP through its `agent_api` REST module — look up eBay products and inventory, push eBay sale orders and read tracking, run the Accounts Paya...
---
name: drivethru-odoo
description: Talk to an Odoo ERP through its `agent_api` REST module — look up eBay products and inventory, push eBay sale orders and read tracking, run the Accounts Payable PO→vendor-bill flow, and schedule MRP production batches onto workcenters. Use whenever the user needs to read from or write to Odoo for eBay fulfillment, vendor-bill matching, or production planning.
version: 0.1.0
emoji: 🏭
homepage: https://www.odoo.com
metadata:
openclaw:
requires:
env: [ODOO_URL, ODOO_API_KEY]
bins: [python3]
primaryEnv: ODOO_API_KEY
envVars:
ODOO_URL:
required: true
description: >
Base URL of the Odoo instance, e.g. `https://staging.yourcompany.odoo.com`.
No trailing path — the skill appends `/agent_api/v1/...`.
ODOO_API_KEY:
required: true
description: >
The `agent_api` access key, sent as the `X-Agent-API-Key` header. Issued
by the Odoo `agent_api` addon. Treat as a secret; never paste into chat.
ODOO_DRY_RUN:
required: false
description: >
When `true`/`1`/`yes`, write actions (create-order, create-bill, schedule,
bulk-schedule, plan) log their intent and return a synthetic result
WITHOUT touching Odoo. Recommended on first deploy.
ODOO_REVIEWER_USER_ID:
required: false
description: >
Default Odoo user id to assign vendor-bill review activities to. The AP
create-bill action also accepts an explicit `reviewer_user_id` per call.
install:
uv:
- requests>=2.28
---
# Odoo agent_api integration
This skill is a thin, JSON-in / JSON-out wrapper over the Odoo **`agent_api`**
REST module (`/agent_api/v1/*`). It authenticates with the `X-Agent-API-Key`
header and covers three domains, one CLI script each:
| Script | Domain | Odoo endpoint prefix |
| ------------------------ | -------------------- | ------------------------------- |
| `scripts/sales.py` | eBay sales/inventory | `/agent_api/v1/ebay/...` |
| `scripts/ap.py` | Accounts Payable | `/agent_api/v1/ap/...` |
| `scripts/production.py` | MRP scheduling | `/agent_api/v1/production/...` |
All three follow the same calling convention:
```bash
echo '<json-args>' | python3 scripts/<script>.py <action>
```
The action is the **first CLI argument**; arguments are a JSON object on
**stdin**. Every script prints a single JSON object on stdout, or
`{"error": {"type": ..., "message": ...}}` with a non-zero exit code on failure.
## Required credentials
The agent host MUST expose **`ODOO_URL`** and **`ODOO_API_KEY`** in the
environment before this skill is invoked. If either is missing, the scripts exit
with `{"error": {"type": "config_error", ...}}` (exit code 2) — stop and tell
the user to set them. Do not prompt the user to paste the key into chat; secrets
come from the environment.
Set **`ODOO_DRY_RUN=true`** to preview writes without mutating Odoo.
## When to use
- "What eBay products / inventory do we have in Odoo?"
- "Push this eBay order into Odoo" / "Is order X shipped — what's the tracking?"
- "Find the PO for vendor X" / "Create the vendor bill for PO 123"
- "Show me the production plan" / "Schedule batch 142 onto Manual Press A"
## When NOT to use
- Generic Odoo XML-RPC / ORM access — this skill only speaks the curated
`agent_api` REST surface, not arbitrary models.
- Editing products, posting bills, or confirming MOs outside the documented
actions — do that in the Odoo UI or extend the `agent_api` addon.
---
## Sales — `scripts/sales.py`
| Action | Input (stdin JSON) | Notes |
| --------------- | ---------------------------------------------------- | -------------------------------------- |
| `list-products` | _(none)_ | Products in the Odoo 'eBay' category. |
| `inventory` | `{"skus": ["A-1", "B-2"]}` | Stock levels per SKU. |
| `create-order` | an eBay **order object** (see `mock-order`) | Idempotent in Odoo; honors dry-run. |
| `tracking` | `{"odoo_order_id": 123}` | `odoo_order_id` is numeric, not `SO…`. |
| `mock-order` | `{"sku"?, "buyer_index"?, "num_line_items"?}` | **Offline** — generates a test order. |
Typical test flow (dry run): generate a mock order, then push it.
```bash
python3 scripts/sales.py mock-order < /dev/null \
| python3 scripts/sales.py create-order
```
`create-order` returns `{odoo_order_id, odoo_order_name, already_existed,
confirmed, confirm_error, ...}`. `already_existed: true` means Odoo already had
this eBay order — an idempotent skip, not an error.
## Accounts Payable — `scripts/ap.py`
| Action | Input (stdin JSON) |
| ----------------- | -------------------------------------------------------------- |
| `search-pos` | `{"search"?, "vendor"?, "state"?, "limit"?}` |
| `get-po` | `{"po_id": 123}` |
| `update-po-lines` | `{"po_id": 123, "lines": [{"line_id", "price_unit"}], "freight_cost"?, "fees_cost"?}` |
| `create-bill` | `{"po_id": 123, "vendor_bill_number"?, "invoice_date"?, "line_ids"?, "reviewer_user_id"?, "review_note"?, "expected_total"?, "tolerance"?}` |
| `get-bill` | `{"bill_id": 456}` |
| `search-vendors` | `{"search"?, "limit"?}` |
The AP flow is: find the PO (`search-pos` → `get-po`), correct line prices /
freight / fees if needed (`update-po-lines`), then `create-bill`. The bill is
created in **draft**; Odoo's create() override auto-adds fee/freight/misc lines,
and the reviewer receives an Odoo activity to verify and post it. Pass
`expected_total` + `tolerance` (default `0.05`) to have the server flag
mismatches.
## Production scheduling (MRP) — `scripts/production.py`
| Action | Input (stdin JSON) |
| -------------------- | -------------------------------------------------------------- |
| `overview` | `{"batch_detail"?, "batch_limit"?, "unscheduled_only"?}` |
| `list-batches` | `{"unscheduled_only"?, "limit"?, "offset"?}` |
| `get-batch` | `{"batch_id": 142}` |
| `schedule` | `{"batch_id", "primary_workcenter_id"?, "production_center_id"?, "date_planned_start"?, "date_planned_finished"?, "activity_message"?}` |
| `plan` | `{"batch_id": 142}` |
| `bulk-schedule` | `{"atomic"?, "updates": [{"batch_id", ...fields}]}` |
| `list-workcenters` | `{"active_only"?}` |
| `get-workcenter` | `{"workcenter_id": 3}` |
| `production-centers` | _(none)_ |
| `decoration-methods` | _(none)_ |
Start a planning pass with `overview` (one round-trip: open batches +
workcenters with their current load + reference data). Pull `get-batch` for the
batches you intend to place (it returns `eligible_workcenters`,
`eligible_production_centers`, decoration readiness, and per-MO durations), then
write decisions with `schedule` (single) or `bulk-schedule` (many).
The four writable scheduling fields are `primary_workcenter_id`,
`production_center_id`, `date_planned_start`, `date_planned_finished`. Partial
updates are fine. The server applies them in safe order and auto-derives
`production_center_id` from the workcenter and `date_planned_finished` from the
start unless you set them explicitly. `plan` runs Odoo's native slot allocator
and requires a workcenter to already be set.
### Example: schedule one batch
```bash
echo '{"batch_id": 142, "primary_workcenter_id": 3,
"date_planned_start": "2026-06-10T14:00:00",
"activity_message": "Auto-scheduled by agent"}' \
| python3 scripts/production.py schedule
```
---
## Errors
Scripts exit non-zero and print `{"error": {...}}` on failure:
- `config_error` (exit 2) — `ODOO_URL` / `ODOO_API_KEY` missing or malformed.
- `api_error` — Odoo returned a non-2xx (includes `status` and `body`). `401`
means a bad `ODOO_API_KEY`; `404` on `get-*` means the record doesn't exist.
- `connection_error` — Odoo unreachable / timed out.
- `validation_error` — bad input JSON or missing required field.
- `unknown_action` / `usage` (exit 2) — bad CLI invocation; the message lists
the valid `actions`.
Surface the human-readable `message` to the user. Do not retry on
`config_error`, `validation_error`, or a `401` `api_error`.
## Safety
- Treat `ODOO_API_KEY` as a secret — the scripts read it from the environment
and never echo it.
- Use `ODOO_DRY_RUN=true` until you've confirmed the data mapping. Confirm
vendor-bill creation and production schedule writes with the user before
running them against a live (non-dry-run) Odoo.
## References
- [`references/agent_api_endpoints.md`](references/agent_api_endpoints.md) — the
full endpoint surface and request/response shapes.
- [`references/production_scheduling.md`](references/production_scheduling.md) —
the MRP data model (batches, workcenters, production centers, decoration
methods) and how the four scheduling fields interact.
don't have the plugin yet? install it then click "run inline in claude" again.