Docs / API and agents
Forms API
Suppliers design and publish forms with an assistant, ask an applicant to fill one in on an application, and read the submitted answers.
A form is a list of typed questions in sections. A supplier edits a draft, publishes it as an immutable numbered version, and asks an applicant to fill it in on one application. The applicant saves and submits answers; the supplier reads them once they are submitted.
Who can do what#
| Permission | Role | Allows |
|---|---|---|
forms.manage | supplier owner or administrator | create, edit, publish, archive forms; use the assistant |
forms.request | supplier credit team | ask an applicant for a form on an application; read submitted answers |
forms.respond | the applicant's own account | read, save and submit the forms requested on their own application |
Another organization's form or application answers 404.
Endpoints#
| Method and path | What |
|---|---|
GET /forms, POST /forms | list the supplier's forms (forms.manage or forms.request, so the credit team can pick one); create one from a title (forms.manage) |
GET /forms/:id | the draft, the latest published version and whether the draft has unpublished changes |
PUT /forms/:id/draft | save the draft; it is validated as a whole (400 names the first problem) |
POST /forms/:id/publish | freeze the draft as version n+1; publishing an unchanged draft returns the existing version with unchanged: true |
DELETE /forms/:id | archive; responses keep their version |
POST /forms/:id/assistant | body definition and messages; returns reply, the edited definition, applied and rejected operations. Nothing is saved |
POST /applications/:id/form-requests | body templateId; pins the latest published version. 409 when that form is already waiting or a decision was recorded |
GET /applications/:id/form-responses | supplier view; answers is null until submitted |
GET /applicant/applications/:id/form-responses | applicant view, saved answers included |
PUT /form-responses/:id/answers | save work in progress (shape and size only, at most 64 KB) |
POST /form-responses/:id/submit | body answers; validated against the pinned version |
Question types and how answers are stored#
| Type | Answer |
|---|---|
text, textarea, email, phone, select | trimmed string |
number | number |
money | whole cents (integer) |
date | YYYY-MM-DD |
yes_no | boolean (mustBeYes makes it a consent) |
multiselect | list of option values |
address | {street1, street2?, city, state, zip} (US) |
tax_id | nine digits (EIN); stored without dashes |
file | list of document ids |
repeater | list of rows, each an object of simple answers |
content | none (explanatory text) |
A question can be shown only when an earlier answer matches (visibleWhen). An answer to a hidden question is dropped on submit and a hidden question is never required. An id the version does not contain is an error (the form changed; reload it).
Answers are stored sealed (AES-GCM, bound to the response and the version), never as readable JSON. A file answer holds document ids only: the file itself is an ordinary application document, uploaded with
POST /applications/:id/documentsand the question's document type, so it is scanned, released only when clean, downloaded through a short-lived link and kept on the application's retention clock. On submit each id must be a live document of that application, of the type the question asked for, uploaded by the applicant, and not rejected by the scan.
Errors#
| Status | When |
|---|---|
| 400 | invalid definition, messages or answers. A submit returns details with one message per question id |
| 403 | the role lacks the permission |
| 404 | not found, or it belongs to another organization or customer |
| 409 | already requested, already submitted, or the application can no longer change (application_closed) |
| 413 | the form is too large for the assistant |
| 429 | 40 assistant requests per user per hour |
| 502 | the model returned something that is not the expected JSON (ai_invalid_json) |
| 503 | AI is not configured or the daily spending cap was reached |
The assistant only proposes edits. Each operation is checked against the whole form (ids unique, conditions look backwards only, limits), one that fails is reported and the others still apply, and the supplier keeps or discards the result before saving and publishing. The model used is the one staff chose for the "Form builder assistant" flow; see the AI API.