# Prompt Generator Website — API v1

Turn a project description into a full build specification and the agent files that go with it
(`AGENTS.md`, `CLAUDE.md`, `.cursor/rules/project.mdc`, `.cursorrules`, `.windsurfrules`,
`.github/copilot-instructions.md`).

- Base URL: `https://prompt-generator-website.com/api/v1`
- JSON in, JSON out, UTF-8. CORS is open (`Access-Control-Allow-Origin: *`).
- MCP (streamable HTTP, stateless): `https://prompt-generator-website.com/mcp`
- CLI and stdio MCP server: `npx specpack` — https://github.com/THE-KIPDEV/specpack

## Authentication

Optional. Send `Authorization: Bearer pgw_…` with a key created in
[your account](https://prompt-generator-website.com/dashboard/account). Without a key the call is
anonymous and counted against the caller's IP address.

## Quotas

| | Free (anonymous or account) | Pass — 7 days, $5 once | Pro — $9/month |
|---|---|---|---|
| Specs | 2 in total | unlimited | unlimited |
| AI drafts | 3 in total | 30 | 100 per month |

A call over quota returns `402 quota_exceeded` with an `upgrade_url`.

## Errors

Every error is an HTTP status plus:

```json
{ "error": { "code": "quota_exceeded", "message": "…", "upgrade_url": "https://prompt-generator-website.com/pricing" } }
```

| code | status |
|---|---|
| `invalid_request` | 400 |
| `unauthorized` | 401 (unknown or revoked key) |
| `quota_exceeded` | 402 |
| `not_found` | 404 |
| `rate_limited` | 429 |
| `server_error` | 500 |
| `ai_unavailable` | 503 |

## GET /types

```json
{ "types": [ { "id": "saas", "label": "SaaS Application", "description": "Web application with subscription, dashboard, auth" } ] }
```

Ids: `saas`, `ecommerce`, `business`, `marketplace`, `blog`, `webapp`, `landing`.

## GET /questions?type=saas

The questionnaire for one project type: universal questions first, then the type-specific ones.

```json
{
  "type": "saas",
  "questions": [
    {
      "id": "main_goal",
      "label": "What is the main goal of the website?",
      "type": "select",
      "required": true,
      "section": "The Project",
      "options": [ { "value": "sell_subscription", "label": "Sell a subscription" } ]
    },
    {
      "id": "saas_trial_days",
      "label": "Trial length",
      "type": "number",
      "required": false,
      "section": "Pricing",
      "condition": { "field": "saas_has_trial", "values": ["1"] }
    }
  ]
}
```

`type` is one of `text`, `textarea`, `select`, `radio`, `multiselect`, `boolean`, `number`.
Optional keys: `help`, `placeholder`, `options`, `condition` (ask the question only when the answer to
`field` is one of `values`; `"1"` / `"0"` stand for `true` / `false`).

Answer values: `text`, `textarea`, `select`, `radio` → string (an option `value` for select/radio);
`multiselect` → array of option values; `boolean` → `true` / `false`; `number` → number.

## POST /specs

```json
{ "type": "saas", "answers": { "project_name": "Ledgerly", "project_description": "Invoicing for freelancers…" } }
```

`project_name` and `project_description` are required; every other answer is optional and falls back
to a sensible default. Unknown keys are ignored. The engine is deterministic: the same answers always
return the same bytes. Counts one spec.

`201`:

```json
{
  "id": 42,
  "type": "saas",
  "project_name": "Ledgerly",
  "created_at": "2026-09-18T15:00:00Z",
  "url": "https://prompt-generator-website.com/prompt/42",
  "spec": "# Complete Specification: Ledgerly\n…",
  "files": {
    "spec.md": "…",
    "AGENTS.md": "…",
    "CLAUDE.md": "…",
    ".cursor/rules/project.mdc": "…",
    ".cursorrules": "…",
    ".windsurfrules": "…",
    ".github/copilot-instructions.md": "…",
    "README.md": "…"
  },
  "usage": { "plan": "free", "specs_used": 1, "specs_limit": 2, "ai_used": 0, "ai_limit": 3 }
}
```

`url` opens the spec on the website for its owner (the account behind the key).

## POST /drafts

AI-assisted: turn a plain-language description into a complete answer set. Takes 10–40 seconds.
Counts one AI draft.

```json
{ "description": "A booking app for dog groomers with deposits and SMS reminders", "type": "saas" }
```

`type` is optional (the model picks one). `description`: 10 to 4000 characters.

`200`:

```json
{
  "type": "saas",
  "answers": { "project_name": "GroomBook", "project_description": "…", "main_goal": "sell_subscription" },
  "assumptions": [ "Assumed Stripe for deposits because none was named." ],
  "usage": { "plan": "free", "specs_used": 0, "specs_limit": 2, "ai_used": 1, "ai_limit": 3 }
}
```

`answers` can be sent unchanged to `POST /specs`. Review `assumptions`: they are the choices the
description did not settle.

## GET /me

Plan and usage for the key (or for the caller's IP when anonymous).

```json
{ "plan": "pass", "plan_until": "2026-09-25T15:00:00Z", "email": "you@example.com",
  "usage": { "plan": "pass", "specs_used": 5, "specs_limit": null, "ai_used": 2, "ai_limit": 30 } }
```

`specs_limit` / `ai_limit` = `null` means unlimited. `email` is `null` when anonymous.

## GET /specs · GET /specs/{id}

Key required. `GET /specs` lists your specs (`{ "specs": [ { "id", "type", "project_name", "created_at" } ] }`,
newest first, 100 max). `GET /specs/{id}` returns the same body as `POST /specs`.
