Forms API

Schema-driven forms collect structured answers from users and agents. Each form is a JSON Schema (with form-specific extensions) plus lifecycle and submission policy settings. Answers are stored as submissions only — credit rewards are claimed separately through bounty programs (POST /me/bounty), not on submit.

The belt CLI exposes forms as belt form (list, get, fill, submissions). Customer-discovery survey prompts are backed by platform forms under infsh/<question_id>. Programs that pay for a form set proof_type: form and proof_form to that ref (for example infsh/discovery); after you submit, claim with proof_id set to the submission id. See Survey, Bounties, and CLI setup — Forms.

Requires API key scopes apps:read (list and read forms and submissions), apps:write (create and update forms), and user:write (submit answers). Listing your own submissions across forms uses user:read.

→ REST overview — response format


Form object

FieldDescription
namespaceTeam namespace (workspace username)
nameImmutable slug; address as namespace/name
title, descriptionDisplay text
schemaJSON Schema for answers (see Schema)
statusdraft, open, or closed — only open accepts submissions
submit_policyonce_per_user, once_per_team, or many

Resolve a form by ref: GET /forms/{namespace}/{name}.


List forms

GET /forms or POST /forms/list

Cursor pagination (limit, cursor). Pass include_others: true in the POST body (or the equivalent query flag) to include public forms owned by other teams.

GET /forms/count returns a total for the same filters.


Get a form

GET /forms/{id} — by form ID.

GET /forms/{namespace}/{name} — by stable ref (preferred for scripts and the CLI).


Create a form

POST /forms

FieldTypeRequiredDescription
namestringYesSlug in your team's namespace
titlestringYesDisplay title
descriptionstringNoLonger description
schemaobjectNoJSON Schema for answers
submit_policystringNoDefault once_per_user
visibilitystringNoprivate, team, org, public, or unlisted

Creating and updating forms needs the invitation-only feature:forms entitlement; without it the API returns 403 feature_not_available (see Entitlement requests). New forms start in draft. Open them with PATCH /forms/{id} (status: "open") before accepting submissions.


Update a form

PATCH /forms/{id} or PUT /forms/{id}

Patch fields: title, description, schema, status, submit_policy.

PUT /forms/{id}/visibility updates visibility without replacing the whole form.

DELETE /forms/{id} removes the form.


Submit answers

POST /forms/{id}/submissions

FieldTypeRequiredDescription
dataobjectYesAnswers validated against schema
sourcestringNoClient id (CLI sends cli)
agentstringNoAgent runtime (e.g. cursor)
contextstringNoFreeform context (recent commands, page path)

Response (SubmitFormResponse):

FieldDescription
submissionStored row (id, data, source, agent, …)

To earn credits for a program that uses proof_type: form, call POST /me/bounty with proof_id set to submission.id after a successful submit. The program's proof_form must match this form's namespace/name.

Errors:

HTTPCodeCause
409form_closedstatus is not open
409already_submittedsubmit_policy has no room for another answer from you or your team
422validation_errorAnswers failed schema validation, or an answer is fill-in placeholder text; meta lists every field error

List submissions

On a form (owners): GET /forms/{id}/submissions, POST /forms/{id}/submissions/list, GET /forms/{id}/submissions/count

Yours across forms: GET /me/submissions, POST /me/submissions/list, GET /me/submissions/count

GET /forms/{id}/submissions/{submission_id} returns one submission.


Schema

Forms use JSON Schema for answer shape. The web app and belt form share the same interpretation:

  • Question types use x-widget (for example short_text, single_choice, rating, yes_no).
  • Conditional fields use x-visible-when (same semantics as the app: malformed or forward references are ignored).
  • A question is required when it is in the top-level required list, when its property sets x-required: true, or when an allOf[].then.required list (standard JSON Schema) names it.
  • Minimum answer length (for example on survey prompts) comes from JSON Schema minLength on the question property, not from bounty program settings.

Answers are a single JSON object keyed by question key (property name). Hidden questions should be omitted; blank optional answers are dropped before submit.


Survey alias

POST /me/survey and GET /me/survey remain the legacy entry points the CLI uses for customer-discovery questions. Each question_id maps to the platform form infsh/<question_id> whenever that form exists, independent of bounty programs; an unknown id returns 400 unknown question. Prefer the Forms API for new integrations that are not survey-specific.

→ Workspaces API — Survey · CLI — Feedback

we use cookies

we use cookies to ensure you get the best experience on our website. for more information on how we use cookies, please see our cookie policy.

by clicking "accept", you agree to our use of cookies.
learn more.