# Hosted and local environments

> The hosted platform is the default for everything. How to point a package at a different gateway, and how to run one locally for development.

## Hosted (default)

| | URL |
|---|---|
| Gateway | `https://api.zanora.dev` |
| Console | `https://console.zanora.dev` |
| Demo seller, REST | `https://demo-seller.zanora.dev/ocr` (`POST`, body `{ "imageUrl": "…" }`, $1.00) |
| Demo seller, MCP | `https://demo-seller.zanora.dev/mcp` (tool `extract_invoice`, $1.00) |
| API health | `https://api.zanora.dev/health` |

The hosted platform handles real money: accounts, listings, balances and receipts you create there are permanent.

> **Tip — The demo seller is always available:**
>
> It's a verified seller selling the same OCR function over both protocols at the same price, so you can test a buying integration on day one before any other seller exists. The REST and MCP versions return the same answer and the same `responseHash`.

## Choosing the gateway

Every package uses the hosted gateway, `https://api.zanora.dev`, unless you name another one.

| Tool | Setting | Default |
|---|---|---|
| `@zanora/mcp`, `@zanora/mcp-proxy` | `ZANORA_GATEWAY_URL` | `https://api.zanora.dev` |
| `@zanora/sdk` | `new ZanoraAgent({ gatewayUrl })`, `new ZanoraClient({ gatewayUrl })` | `https://api.zanora.dev` |
| `@zanora/middleware-mcp` | `zanoraSeller({ gatewayUrl })`, or `ZANORA_GATEWAY_URL` | `https://api.zanora.dev` |
| `@zanora/middleware-express` | `new HttpBackend({ gatewayUrl, apiKey })`, or positionally `new HttpBackend(gatewayUrl, apiKey)` | `https://api.zanora.dev` |
| Starter scripts in the repository | `ZANORA_GATEWAY` | `https://api.zanora.dev` |

A seller's middleware and the capability it serves must use the **same** gateway. If they don't, buyers get `402` forever, or the call fails with `PROVIDER_NOT_FOUND` when it completes.

## Running a gateway locally

For development against a local gateway, with the platform repository checked out:

```bash
PORT=8080 ZANORA_REQUIRE_AUTH=true ZANORA_API_KEYS=admin-boot \
  ZANORA_SIGNUP_DEV_ECHO=true NODE_OPTIONS=--conditions=development \
  npx tsx packages/platform/src/server.ts
```

- `ZANORA_REQUIRE_AUTH=true` makes keys identify a tenant, which is how the hosted platform behaves.
- `ZANORA_API_KEYS=admin-boot` gives you an operator key, so you can verify your own test seller.
- `ZANORA_SIGNUP_DEV_ECHO=true` returns the signup token in the response, so you don't need an inbox. **Local development only.**

A local gateway keeps state in memory unless you set `ZANORA_DATABASE_URL`, and its payment rails are mocks. `POST /v1/wallets/:id/fund` credits a wallet instantly there. On the hosted platform that route returns `NOT_SUPPORTED`, because real funding has to come through a card or a transfer.

## Differences from the hosted platform

| | Local gateway | Hosted platform |
|---|---|---|
| Signup token | in the response (dev echo) | emailed. The link opens the console |
| Funding | `POST /v1/wallets/:id/fund`, instant | card top-up or USDC deposit, credited when the rail confirms |
| Seller verification | you do it with the admin key | a Zanora operator does it |
| Seller URL | `localhost` works if the agent is on the same machine | must be reachable from wherever buyers' agents run |
