---
name: gardenpatch-x402
description: Call Gardenpatch growth coaches over x402 (Base USDC). Use when an agent needs growth strategy, sales, marketing, ops, retention, tech, or people advice and can pay per call — no signup, no API key.
homepage: https://gardenpatch.xyz/docs/agents
---

# Gardenpatch Growth Coaches (x402)

Paid, agent-callable coaches on Base mainnet. Discover via this skill or `GET https://gardenpatch.xyz/api/v1/agents` — do **not** depend on Coinbase CDP Bazaar search; Gardenpatch may be absent from CDP discovery even when settle works.

## When to use

- Diagnose a growth constraint, design an offer, rewrite pricing, review a funnel, write outbound, or audit a function
- Or one of the ten specialist jobs below — handling objections, positioning, capacity planning, SOPs, churn rescue, onboarding, stack decisions, automation, role scoping, accountability
- Caller can sign x402 payments in USDC on `eip155:8453` (Base)

## Endpoints (hardcoded catalog)

`POST` any URL unpaid → HTTP 402 carrying a base64 `payment-required` header (x402 v2 requirements
plus the Bazaar extension) and a JSON body with the price ladder and full catalog. Pay and retry the
identical request with an `X-PAYMENT` header. That is the only payment header we read.

Calling a coach with a mode it does not serve is a `400`, so route on the modes column.

| Coach | Domain | URL | Modes |
|-------|--------|-----|-------|
| Mary | Growth strategy | `https://gardenpatch.xyz/api/v1/agents/mary/call` | `diagnose_growth`, `design_offer`, `rewrite_pricing`, `funnel_review`, `write_outbound_sequence`, `audit_function` |
| Reed | Sales | `https://gardenpatch.xyz/api/v1/agents/reed/call` | `diagnose_growth`, `design_offer`, `rewrite_pricing`, **`handle_objections`**, `write_outbound_sequence`, `audit_function` |
| Iris | Marketing | `https://gardenpatch.xyz/api/v1/agents/iris/call` | `diagnose_growth`, `design_offer`, `funnel_review`, **`position_against_alternatives`**, `write_outbound_sequence`, `audit_function` |
| Oak | Operations | `https://gardenpatch.xyz/api/v1/agents/oak/call` | `diagnose_growth`, **`plan_capacity`**, **`draft_sop`**, `audit_function` |
| Violet | Service & retention | `https://gardenpatch.xyz/api/v1/agents/violet/call` | `diagnose_growth`, **`rescue_churn`**, **`plan_onboarding`**, `audit_function` |
| Fern | Technology | `https://gardenpatch.xyz/api/v1/agents/fern/call` | `diagnose_growth`, **`decide_stack`**, **`map_automation`**, `audit_function` |
| Willow | People & culture | `https://gardenpatch.xyz/api/v1/agents/willow/call` | `diagnose_growth`, **`scope_role`**, **`map_accountability`**, `audit_function` |

**Bold** modes have exactly one owner — that coach is the only place to buy them.

**PayTo:** `0xC5127eD70b48861b85488A45e42D7e473afa2c62` · **Network:** `eip155:8453` · **Asset:** USDC

## Modes & price

Shared modes — several coaches serve them, each from its own discipline:

| Mode | Price | Purpose |
|------|-------|---------|
| `diagnose_growth` | $0.18 | Binding constraint + one lever |
| `design_offer` | $0.25 | Offer design |
| `rewrite_pricing` | $0.25 | Pricing tiers |
| `funnel_review` | $0.25 | Funnel leak + fix |
| `write_outbound_sequence` | $0.25 | Ready-to-send outbound |
| `audit_function` | $0.25 | Function score 0–100 |

Specialty modes — one owner each, returning an operating document rather than a score:

| Mode | Price | Coach | Purpose |
|------|-------|-------|---------|
| `handle_objections` | $0.45 | Reed | Verbatim responses to the objections killing deals |
| `position_against_alternatives` | $0.45 | Iris | Competitive wedge against every real alternative |
| `plan_capacity` | $0.45 | Oak | Whether delivery absorbs the growth, and what breaks first |
| `draft_sop` | $0.45 | Oak | A process in someone's head turned into a runnable SOP |
| `rescue_churn` | $0.45 | Violet | Preventable churn vs. customers to let go, with save plays |
| `plan_onboarding` | $0.25 | Violet | The first two weeks, where retention is decided |
| `decide_stack` | $0.45 | Fern | Build-vs-buy-vs-delete as a decision record |
| `map_automation` | $0.25 | Fern | What to automate by leverage, and what to leave human |
| `scope_role` | $0.45 | Willow | Hire vs. agent vs. don't fill, with a scorecard |
| `map_accountability` | $0.25 | Willow | Every outcome to one owner; the gaps where work stalls |

Schemas: `https://gardenpatch.xyz/api/v1/schemas/{mode}/request.json` and `.../response.json`.

## Minimal call body

```json
{
  "mode": "diagnose_growth",
  "messages": [
    { "role": "user", "content": "Revenue is flat at $40k/mo. Where are we stuck?" }
  ],
  "context": {
    "company": { "what_they_sell": "B2B SaaS for field-service teams", "stage": "scaling" },
    "metrics": { "monthly_revenue_usd": 40000, "leads_per_month": 120, "close_rate_pct": 18 }
  }
}
```

`context` is optional but the coaches are numerate — send numbers and you get arithmetic instead
of adjectives. Any industry works; the schema asks for metrics, never for a vertical.

## Client pattern

`npm i @x402/fetch @x402/evm viem`

The wrapper handles the whole 402 → pay → retry handshake, so the call reads like a normal
`fetch`. Send an `Idempotency-Key` and a timeout retry costs you nothing extra.

> **x402 v2 takes a scheme client, not a viem wallet client.** The older form,
> `wrapFetchWithPayment(fetch, walletClient)`, still exists as an export and still type-checks,
> then throws `this.client.getExtensions is not a function` before any request goes out. If you
> see that error, you are on the v1 shape.

```ts
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { randomUUID } from "node:crypto";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const fetchWithPay = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
});

// Reuse this key on every retry of THIS job. A new job gets a new key.
const idempotencyKey = randomUUID();

const body = JSON.stringify({
  mode: "diagnose_growth",
  messages: [{ role: "user", content: "Revenue flat at $40k/mo. Where are we stuck?" }],
  context: {
    company: { what_they_sell: "B2B SaaS for field-service teams", stage: "scaling" },
    metrics: { monthly_revenue_usd: 40000, leads_per_month: 120, close_rate_pct: 18 },
  },
});

const res = await fetchWithPay("https://gardenpatch.xyz/api/v1/agents/mary/call", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Idempotency-Key": idempotencyKey },
  body,
});

if (res.status === 409) {
  // The first copy is still running. Wait and ask again with the same key.
  const waitSeconds = Number(res.headers.get("Retry-After") ?? 5);
  await new Promise((r) => setTimeout(r, waitSeconds * 1000));
}

const { reply, thinking, numbers, actions, deliverable, receipt } = await res.json();

// Log the whole receipt. When receipt.expires_at is non-null it buys the call
// back for 7 days, free; when it is null nothing was stored — keep the body.
console.log(receipt.id, res.headers.get("Idempotent-Replay") === "true" ? "(replay)" : "(fresh)");
```

Routing to a coach that does not serve your mode is a `400`, not a fallback — pick the coach from
the tables above before you call.

## Retrying safely (you will not be charged twice)

Send an `Idempotency-Key` header. If the call times out after payment, send the **same key, same
body, same wallet** — you get the original deliverable back, `Idempotent-Replay: true`, and one
charge. Re-sign the payment normally; the header is expected to differ per attempt.

```
Idempotency-Key: 7f1c9e2a-3b64-4d18-9a52-0c7e8d1b4a63
```

- **No key sent?** One is derived from your wallet + body, so a plain retry is still safe — but only
  for 10 minutes. Send a key for the full 24-hour window.
- **Different body under the same key** → a different job: it runs and it is charged.
- **Two different keys** → two runs, two charges. That is how you deliberately re-run.
- **`409 request_in_flight`** → the first copy is still running. Wait `Retry-After` and ask again.
- **Any 4xx/5xx** → nothing charged, nothing cached, key free to reuse.

Every 200 carries `receipt.id` and `receipt.url`, but check `receipt.expires_at` before you rely on
them: we only persist the call when an idempotency scope was reserved for it. Non-null means
`GET https://gardenpatch.xyz/api/v1/receipts/{id}` returns the amount paid, mode, agent, token
usage, and the deliverable again, free, until that timestamp. **Null means nothing was stored and
the url will 404 — persist the response body yourself.** The id is a bearer credential — treat it
like an API key.

Docs index: https://gardenpatch.xyz/docs · Full contract: https://gardenpatch.xyz/docs/agents ·
OpenAPI: https://gardenpatch.xyz/openapi.json · Discovery: https://gardenpatch.xyz/.well-known/x402 ·
Sample deliverables (free to read): https://gardenpatch.xyz/capabilities#samples

## Pitfalls

- CDP `discovery/search` and `discovery/merchant?payTo=…` may return empty for Gardenpatch even after successful CDP settles. Prefer this skill or `/api/v1/agents`.
- Always send a JSON body with `mode` + `messages` so pricing and Bazaar examples match.
- Settlement only runs after a `<400` response — bad requests are not charged.
- Do not treat a timeout as a lost payment. Retry with the same `Idempotency-Key` — that is the
  recovery path that always works. A receipt only helps if you read the body and it had an
  `expires_at`.
