# For Google Forms — API Reference

Versioned machine API for creating Google Forms from plain text.
Base URL: `https://for-google-forms.surveysai.com/api/v1/forgoogleforms`
Machine-readable spec: [`/api/v1/forgoogleforms/openapi.json`](https://for-google-forms.surveysai.com/api/v1/forgoogleforms/openapi.json)

## Quickstart

```bash
# 1. Log in with Google at https://for-google-forms.surveysai.com/ and create
#    an API key in the dashboard (API keys section). Keys look like fgf_...

# 2. Parse / check a form (free):
curl -X POST https://for-google-forms.surveysai.com/api/v1/forgoogleforms/parse \
  -H "Authorization: Bearer fgf_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"form_text": "Customer Feedback\n*Full Name [text]\nRating [linear_scale]"}'

# 3. Create the real Google Form (billed, 10 API credits independently of PRO):
curl -X POST https://for-google-forms.surveysai.com/api/v1/forgoogleforms/forms \
  -H "Authorization: Bearer fgf_YOUR_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3f2b8c1e-7a4d-4f6b-9e21-5c0d8a9b7e64" \
  -d '{"form_text": "Customer Feedback\n*Full Name [text]"}'
```

## Authentication

`Authorization: Bearer fgf_...` — see [auth guide](forgoogleforms-auth-guide.md).
Scopes: `forms:read`, `forms:write`, `validate`, `credits:read`.

## Endpoints

| Method | Path | Auth / scope | Billed |
|---|---|---|---|
| GET | `/capabilities` | public | — |
| GET | `/pricing` | public | — |
| GET | `/openapi.json` | public | — |
| POST | `/parse` | `validate` | free |
| POST | `/validate` | `validate` | free; `use_llm: true` → 2 credits |
| GET | `/forms` | `forms:read` | free |
| POST | `/forms` | `forms:write` | 10 credits |
| GET | `/me` | any key | free |
| GET | `/credits/ledger` | `credits:read` | free |
| POST | `/credits/checkout` | any key | — (payment) |

All request bodies are JSON. Form input is the plain-text format described in
[`QUESTION_TYPES.md`](../QUESTION_TYPES.md) (summary at `/llms.txt`).

### POST /forms

Body: `{"form_text": "..."}`. Optional header `Idempotency-Key: <string>`
(max 255 characters, surrounding whitespace is ignored; use a random value
such as a UUID). The key is scoped to the API key owner's account and to the
action — it never matches another account's request. Repeating a **successful** call with the same key returns
the original result without creating or charging again. Responses:

- `201` — `{status, data: {form_id, google_form_id, form_url, question_count, warnings, charged_credits}}`
- `200` — replay of a previous successful idempotent call (`data.replayed: true`)
- `400` — `missing_form_text`, or `invalid_idempotency_key` (longer than 255 characters)
- `401` — `invalid_api_key`
- `402` — insufficient credits; body contains x402-style `accepts` array with
  top-up instructions (see [payments guide](forgoogleforms-payments-guide.md))
- `403` — `insufficient_scope` (key lacks `forms:write`) or `action_not_allowed`
  (the key's action whitelist excludes form creation)
- `409` — one of:
  - `google_account_not_linked`, `google_token_unreadable` or
    `google_token_refresh_rejected`: the key's owner must log in once more via
    the web so the service can store a valid Google refresh token;
  - `google_scope_missing`: the owner signed in but did not allow Google Forms
    access on Google's consent screen; they must log in via the web again and
    keep "See, edit, create and delete all your Google Forms forms" checked
    (no credit is charged);
  - `credit_reconciliation_required`: the credit account requires manual
    refund/reconciliation resolution;
  - `idempotency_key_conflict`: an earlier call with the same key is still in
    progress or did not succeed (it was refunded). Retry with a **new**
    `Idempotency-Key`.
- `413` — `form_text_too_large` (over 100 kB)
- `422` — `parse_failed` (details in `errors`) or `no_questions` (the `message`
  explains the plain-text format with an example, typically the text was sent
  as YAML, JSON or Markdown); fix and retry
- `429` — rate limit exceeded, or `daily_budget_exceeded` (key's daily credit budget)
- `500` — `create_persistence_failed`: the Google Form was created but could not
  be saved; the credit is refunded
- `502` — `google_forms_error` or `google_token_refresh_failed`: an upstream
  Google call failed; the credit is refunded
- `503` — `api_disabled` (operator kill-switch)

### POST /validate with `use_llm: true`

Billed (2 credits). The same account-scoped `Idempotency-Key` prevents a
double charge on retry, but LLM results are not stored: repeating a key returns
`409 idempotency_key_conflict` instead of a free re-run. Use a new key for each
validation.

### Errors

Errors returned by the API: `{"status": "error", "error": "<code>", "message": "..."}` with
appropriate HTTP status (schema `Error` in the OpenAPI spec; `402` extends it as
`PaymentRequired`). `503 api_disabled` means the operator kill-switch is on.
Exceptions: a rate-limit `429` and an unexpected `500` may have a non-JSON
body, so check the HTTP status first. Every operation lists its full set of
status codes in the OpenAPI spec; a test in CI keeps the spec in sync with the
code.

### POST /credits/checkout

Body: `{"credits": 200..20000, "currency": "usd"|"eur"}`. One credit costs
0.01 in the selected currency. Purchased credits do not expire and do not
require PRO.

## Rate limits

Default 120 requests/hour per API key (creation endpoints lower). Per-action
credit budgets can be set per key (`daily_credit_limit`).

## Versioning and deprecation

- The major version is part of the path (`/api/v1/`). Within `v1`, changes are
  additive only: new operations, new optional request fields, new response
  fields and new error codes. Clients should ignore unknown fields.
- `operationId` values are stable identifiers and are not renamed within `v1`.
- A breaking change ships as `/api/v2/` alongside `v1`. `v1` then stays
  available for at least 6 months, the deprecation is announced in this
  document and in `info.description` of the OpenAPI spec, and deprecated
  operations are marked `deprecated: true`.
- `info.version` in the spec follows semantic versioning of the contract.
