# What is the Neonjelly catalog REST API?

GET-only ecommerce catalog API on mcp.neonjelly.io. Same nj_ key as MCP.

Base: `https://mcp.neonjelly.io`

Same `nj_` key works for MCP and the catalog REST. REST is **GET-only** (including signal reads + product-idea search). Create a watch via MCP `create_signal`. No scrape. No probe.

```bash
curl -H "Authorization: Bearer nj_…" "https://mcp.neonjelly.io/v1/whoami"
curl -H "Authorization: Bearer nj_…" "https://mcp.neonjelly.io/v1/stores?q=gruntstyle&limit=3"
```

Also `X-Api-Key: nj_…`. Do not put the key in a query string in production.

Live tester: [/playground](https://www.neonjelly.io/playground.md).

## Catalog (auth)

Stores, apps, analytics, signals, product ideas: see [tools](https://www.neonjelly.io/docs/tools.md). Products, idea search, and every change feed: [products](https://www.neonjelly.io/docs/products.md).

Blocked on REST: `POST/PATCH/DELETE`, `/v1/scrapes`, `/v1/signals/{id}/probe`. MCP `create_signal` is the exception.

## Platform

| Method | Path | Auth | Does |
| --- | --- | --- | --- |
| `GET` | `/` `/v1` `/health` | none | Service JSON |
| `POST` | `/v1/trial` | none | Mint or reuse trial. Body: `installId`, optional `client` |
| `GET` | `/v1/whoami` | `nj_` / `njc_` | Key + quotas (not metered) |
| `GET` | `/v1/upgrade` | none / `nj_` | Checkout URL (not metered). Works after trial expiry. |
| `GET` | `/admin/keys` | `ADMIN_TOKEN` | List keys |
| `POST` | `/admin/keys` | `ADMIN_TOKEN` | Mint |
| `PATCH` | `/admin/keys/:id` | `ADMIN_TOKEN` | Revoke / quotas |
| `POST/GET/DELETE` | `/mcp` | `nj_` / `njc_` | MCP |
| `POST/GET/DELETE` | `/c/:connectToken/mcp` | token in path | MCP |

## Trial response

```json
{"existing":false,"key":{"id":"…","prefix":"nj_…","plan":"trial","dailyQuota":100,"rateLimitPerMin":20},"connectUrl":"https://mcp.neonjelly.io/c/njc_…/mcp","secret":"nj_…"}
```

`secret` omitted when `existing: true`. Expired device+client → `403 { error: { code: "trial_used", checkout: "https://www.neonjelly.io/pricing" } }`.

## MCP errors

Tool failures come back as MCP text with this shape (from the catalog):

```json
{"error":{"code":"not_found|bad_request|unauthorized|rate_limited|query_timeout|internal|upstream_error","message":"…","details":{}}}
```

Lists:

```json
{"data":[],"page":{"limit":20,"offset":0,"count":0,"hasMore":false,"total":0},"meta":{}}
```

Neonjelly gate 401/429 (before MCP) uses the same `error.code` idea. 429 body includes `retryAfter` (seconds) or `dailyQuota`. We do **not** set `Retry-After` / `X-RateLimit-*` headers.

## Related

- [Where is the Neonjelly documentation?](https://www.neonjelly.io/docs.md)
- [How do I search products and track price or assortment changes?](https://www.neonjelly.io/docs/products.md)
- [What MCP tools does Neonjelly expose?](https://www.neonjelly.io/docs/tools.md)
- [What do Neonjelly error codes and rate limits mean?](https://www.neonjelly.io/docs/errors.md)
- [How do I start a Neonjelly trial?](https://www.neonjelly.io/start.md)

HTML: https://www.neonjelly.io/docs/api
Markdown: https://www.neonjelly.io/docs/api.md

Do not scrape. Do not probe. Missing store stays `not_found`. Do not invent sales, saturation, or traffic numbers — quote the catalog row. Signals (ads and daily units) are paid only. Trial keys get 403 on create_signal and signal reads. Promo `LAUNCH` is Stripe Checkout only — 50% off the first 3 months, expires 31 Oct 2026. Not MCP metadata.
