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
Quickstart
# 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.
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 (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, orinvalid_idempotency_key(longer than 255 characters)401—invalid_api_key402— insufficient credits; body contains x402-styleacceptsarray with top-up instructions (see payments guide)403—insufficient_scope(key lacksforms:write) oraction_not_allowed(the key's action whitelist excludes form creation)409— one of:google_account_not_linked,google_token_unreadableorgoogle_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 newIdempotency-Key.
413—form_text_too_large(over 100 kB)422—parse_failed(details inerrors) orno_questions(themessageexplains the plain-text format with an example, typically the text was sent as YAML, JSON or Markdown); fix and retry429— rate limit exceeded, ordaily_budget_exceeded(key's daily credit budget)500—create_persistence_failed: the Google Form was created but could not be saved; the credit is refunded502—google_forms_errororgoogle_token_refresh_failed: an upstream Google call failed; the credit is refunded503—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/). Withinv1, changes are additive only: new operations, new optional request fields, new response fields and new error codes. Clients should ignore unknown fields. operationIdvalues are stable identifiers and are not renamed withinv1.- A breaking change ships as
/api/v2/alongsidev1.v1then stays available for at least 6 months, the deprecation is announced in this document and ininfo.descriptionof the OpenAPI spec, and deprecated operations are markeddeprecated: true. info.versionin the spec follows semantic versioning of the contract.