openapi: 3.1.0 info: title: Jinshuju API v1 version: '1.0' description: | Jinshuju open API v1, for reading and writing forms, tables, entries, views, comments, public queries and other resources. For the product-side documentation see [Jinshuju Open Platform](https://open.jinshuju.net/api_v1). ## Request conventions - Base URL: `https://jinshuju.net/api/v1`; every path is relative to it. - Request headers: `Content-Type: application/json`, `Accept: application/json`, `Authorization` (see below). - Update endpoints use `PATCH` (only the keys present change); `PUT` on the same path is a compatibility alias, handled and validated as `PATCH`. For the entries resource, `PUT` (full replace) and `PATCH` (partial update) mean different things and are listed separately. - Responses are always JSON and carry `Access-Control-Allow-Origin: *`. - The schemas for field definitions (`FieldInput` and each `Input`, `FieldUpdateInput`, `FormCreateInput`, `TableCreateInput`, etc.) branch on the field `type` and carry conditional constraints. ## Authentication - **Bearer Token**: `Authorization: Bearer ACCESS_TOKEN`. Three kinds of token are supported: - Personal access token: acts as that user, on the forms they created or that are shared with them; - Account access token (Enterprise plan): acts across the account, on all of its forms. Endpoints then have no "current user", and create operations are recorded under the account owner; - OAuth 2.0 token: the endpoints it can call are limited by the token's scope; insufficient scope returns `403`. Each endpoint's description states the scope it needs (`forms` / `form_setting` / `read_entries` / `write_entries` / `submit_entries` / `read_contacts` / `users` / `public`). - An invalid or revoked token returns `401`; a plan without API v1 returns `402`. ## Rate limiting Requests are counted per account per hour: every token of the account (its members' personal access tokens, account access tokens and OAuth tokens) draws on one shared quota. The hourly quota comes from the account's plan, unless the account has a quota set individually: | Plan | `plan` code | Requests per hour | |---|---|---| | `免费版` | `free` | 100 | | `专业版` | `pro2` | 1000 | | `专业增强版` | `ent2` | 1000 | | `企业基础版` | `e10` | 20000 | | `企业协作版` | `e20` | 30000 | | `企业高级版` | `e30` | 50000 | | `商业合作版` | `en_cor` | 50000 | Every response to a request that sends `Authorization` carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`, so a caller can pace itself before the quota runs out. Over the quota returns `429` with `Retry-After`; the body (`RateLimitError`) gives the plan code, the limit, when the quota resets and a link to upgrade. ## Error format Business errors always return `{ "error_description": "..." }`; the HTTP status code gives the error category: `400` parameter or data validation failed, `401` not authenticated, `402` not supported by the plan, `403` no permission / quota used up / insufficient scope, `404` resource does not exist or is not accessible, `422` every item of a batch operation failed, `429` rate limit exceeded. ## Pagination List endpoints return `{ total, count, data, next }`. `next` being `null` means this is the last page; pass it back unchanged to get the next page. `skip` sets the starting row (from 0, at most 10000), for reading in parallel slices; `skip` and `next` cannot be passed together. Form, table and entry lists, and the "my submissions" lists, take `limit` for the page size (default 50, max 1000); view entry lists are fixed at 50 per page. The 小金商户 order / refund / payout lists are paged by page number: they return `page_info` (total, page, per_page, total_pages) and an array of records; `limit` defaults to and is capped at 50. `next` (the next page number) is present only when there is a next page; pass it back unchanged. ## Time and time zone System times such as `created_at` / `updated_at` are returned in UTC ISO 8601 (e.g. `2021-09-28T02:59:42.539Z`); date field values are formatted in Beijing time (UTC+8) to the field's precision (e.g. `2012-12-25` or `2012-12-25 12:13`), and are parsed as Beijing time when written. ## Input validation The server validates the path parameters, query parameters and JSON request body of every request against this document (except the multipart body of upload endpoints). - An invalid request returns `400` directly, with the response body `{ error_description, errors: [{ pointer, message, code }] }`; a request body that is not `application/json` returns `415`. - Keys not listed in a request body schema are errors (except the field values of entry writes, which the form's field definitions decide). servers: - url: https://jinshuju.net/api/v1 description: Production security: - bearerAuth: [] tags: - name: Forms description: 'Forms: list, structure, create and edit, plus field display rules, cooperators, copy, move and other related operations.' - name: Form Settings description: 'Form settings: submission settings, access policy, Webhook, theme, closing rules, exam / evaluation scene settings.' - name: Plugins description: Plugin center plugins (check-in for now). A plugin campaign is bound to one form, and only its creator can see and change it. The account must have enabled the plugin in the plugin center, or the request returns 402. - name: Entries description: 'Form entries: list, query, create, update, delete and batch operations.' - name: Tables description: 'Tables (kind=table): structure and entries; field types are limited to the column types tables support.' - name: Views description: Form / table views (view filters, sort, column configuration) and reading entries through a view. - name: Comments description: Entry comments. - name: Fill description: 'Fill links: read the fill page (`/f/`, `/v/`) as a submitter and submit entries through it.' - name: OpenSearch description: Public queries. - name: Folders description: Folders. - name: Predefined Choices Sets description: Predefined choice sets. - name: Templates description: Using templates. - name: Contacts description: Contacts. - name: Account description: 'Current user and account: members, e-invoices, payment history, SMS signature review status.' - name: Trade description: '小金商户: merchant and onboarding progress, payment orders, transaction statistics, refunds and payouts.' - name: Uploads description: Uploading attachments, form images and import files. - name: Utilities description: Utility endpoints. paths: "/forms": get: tags: - Forms summary: List forms operationId: listForms description: | Returns the forms visible to the current identity (`kind=form`, excluding tables and quick payment forms). A personal token returns the forms the user created and those shared with them; an account token returns every form in the account. By default sorted by id descending (that is, by creation time descending), and `next` is the id of the first row of the next page; when `sort` is passed, rows are sorted by the given field and `next` becomes `row:`. 50 per page by default, adjustable with `limit` (max 1000). - Each row carries `entries_count` (entry count) and `last_entry_created_at` (when the last entry was received), usable with `filters` / `sort`. - With `include_transactions=true`, forms bound to a payment account carry `transactions` payment statistics. OAuth scope: forms parameters: - $ref: '#/components/parameters/FormsQ' - $ref: '#/components/parameters/FormsFilters' - $ref: '#/components/parameters/FormsSort' - $ref: '#/components/parameters/FormsNext' - $ref: '#/components/parameters/FormsSkip' - $ref: '#/components/parameters/PageLimit' - $ref: '#/components/parameters/IncludeTransactions' responses: '200': description: Form list content: application/json: schema: $ref: '#/components/schemas/FormListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' post: tags: - Forms summary: Create a form operationId: createForm description: | Creates a form from a list of field definitions and returns the full form structure. `name` and `fields` are required. - `scene` sets the form's scene; exam / evaluation question types (such as `SingleSelect`, `FillInBlank`) can only be used in the scenes that support them. - `layout=card` (paged) does not support PageBreak, Matrix*, TableField, GoodsField, ESignatureField, FormAssociation, MultipleBlanksField or any kind of Widget field. - The folder named by `folder_token` must be manageable and of kind form; otherwise returns 404 / 400 respectively. - `setting` accepts only whitelisted keys (see `FormSettingWriteInput`); `setting.notification_rules` replaces, as a whole, the notification rules created through the API. - The returned form structure carries `url` (the public fill URL). OAuth scope: forms requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormCreateInput' responses: '201': description: Created; returns the form structure content: application/json: schema: $ref: '#/components/schemas/Form' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': description: The folder named by folder_token does not exist or cannot be managed content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}": parameters: - $ref: '#/components/parameters/FormToken' get: tags: - Forms summary: Show a form's structure operationId: getForm description: | Returns the form's name, public fill URL (`url`), description, field definitions and settings. Each element of `fields` is a single-key object `{ "": {...} }`, in field order. The following are included when the matching parameter is `true`: - `include_analytics`: each analysable field's definition carries `analytics`; - `include_theme`: carries `theme` (the form theme); - `include_field_rules`: carries `field_rules` (field display rules); - `include_extended_attributes`: carries `extended_attributes` (source-tracking links); - `include_transactions`: carries `transactions` (payment statistics) when the form is bound to a payment account. OAuth scope: forms responses: '200': description: Form structure content: application/json: schema: $ref: '#/components/schemas/FormDetail' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' parameters: - name: include_analytics in: query required: false description: Whether to include `analytics` on each analysable field (the aggregate functions available, whether it can be grouped by, the shape of its summary). Defaults to false. schema: type: boolean default: false - name: include_theme in: query required: false description: When `true`, includes `theme` (the form theme). schema: type: boolean default: false - name: include_field_rules in: query required: false description: When `true`, includes `field_rules` (field display rules, the same as the `data` of `GET /forms/{form_token}/field_rules`). schema: type: boolean default: false - name: include_extended_attributes in: query required: false description: When `true`, includes `extended_attributes` (source-tracking links, the same as the `data` of `GET /forms/{form_token}/extended_attributes`). schema: type: boolean default: false - $ref: '#/components/parameters/IncludeTransactions' patch: tags: - Forms summary: Edit a form operationId: updateForm description: | Edits a form partially; also accepts `PUT`. The request body must contain at least one of `name` / `description` / `fields` / `setting` / `field_rules`, otherwise returns 400. - `fields` is changed incrementally through four kinds of operation, `add` / `remove` / `update` / `update_choices`; fields, choices and api_codes not mentioned are all kept; `update[].type` changes a field's type in place, and a change that clears entry data must carry `confirm_data_loss: true`. - `field_rules` does `add` / `remove` / `update` on rules located by the `index` that `GET /forms/{form_token}/field_rules` returns. - `setting`, as on create, accepts only whitelisted keys. Returns the full updated form structure. OAuth scope: forms requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormUpdateInput' responses: '200': description: Updated; returns the form structure content: application/json: schema: $ref: '#/components/schemas/Form' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' post: tags: - Entries summary: Create an entry (legacy path) operationId: createEntryLegacy deprecated: true description: | Legacy alias of `POST /forms/{form_token}/entries`, with identical behavior. New integrations should use the new path. OAuth scope: write_entries requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryInput' responses: '201': description: Created content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/EntryValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/fields/check": get: tags: - Forms summary: Check whether fields already hold data description: | Use before deleting a field or choice: checks in batch whether fields (or single choices of a field) already have submitted entries. Deleting a field or choice that still has entries deletes those entries with it, and they cannot be recovered. Matches the check the web editor runs before deleting. - Put every deletion target of one edit in the `checks` of a single call (at most 100, may span several fields); `results` matches `checks` one to one, in order. - When a target cannot be checked (for example, the field does not exist), its row returns `unavailable` with the reason; the other targets return as usual. - Returns 400 when `checks` is missing, empty, over 100, not a JSON array, or has an item that is not an object. OAuth scope: forms operationId: checkFormFieldData parameters: - $ref: '#/components/parameters/FormToken' - $ref: '#/components/parameters/FieldDataChecks' responses: '200': description: Per-item check results content: application/json: schema: $ref: '#/components/schemas/FieldDataCheckResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/fields/preview_convert": get: tags: - Forms summary: Preview a field type change description: | Use before changing a field's type (the field's `type` in PATCH /forms/{form_token}): changes no data, and counts, from the field's current entries, how many would be kept and how many cleared after the conversion. The conversion happens on the original field (api_code and data column unchanged), so only entry data is affected; matches the preview the web editor shows before converting. - Put every conversion of one edit in the `checks` of a single call (at most 20); `results` matches `checks` one to one, in order. - `supported=false` means the field cannot be converted to the target type, and the actual edit is refused too. - When converting multi-line text to a choice field such as single choice / multiple choice, also returns `choice_count`, the number of choices that would be generated from existing entries, and `choice_limit_exceeded`, whether that exceeds the choice limit (when it does, the conversion is refused rather than truncated). - When an item cannot be previewed (the field does not exist, `target_type` is not a type available to this form, etc.), its row returns `unavailable` with the reason; the other items return as usual. - Returns 400 when `checks` is missing, empty, over 20, not a JSON array, or has an item that is not an object. OAuth scope: forms operationId: previewFormFieldTypeChange parameters: - $ref: '#/components/parameters/FormToken' - $ref: '#/components/parameters/FieldTypeChangeChecks' responses: '200': description: Per-item preview results content: application/json: schema: $ref: '#/components/schemas/FieldTypeChangePreviewResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/entries": parameters: - $ref: '#/components/parameters/FormToken' get: tags: - Entries summary: List entries operationId: listEntries description: | Returns form entries page by page, 50 per page by default, set with `limit` (max 1000). Sorted by serial number ascending by default; `next` is the serial number of the first entry of the next page. - `filters` / `keyword` trigger a conditional query; `created_at` returns only entries created at or after that time (and sorts by creation time instead); in both these cases, and when `sort` is passed, `next` becomes a row offset. - `fields` returns only the given fields (the serial number is always returned). - Each entry is keyed by field api_code (a field with api_code_alias set is keyed by its alias); for the value shapes see `EntryData`. OAuth scope: read_entries parameters: - $ref: '#/components/parameters/EntriesFields' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' - $ref: '#/components/parameters/EntriesSort' - $ref: '#/components/parameters/EntriesCreatedAt' - $ref: '#/components/parameters/EntriesNext' - $ref: '#/components/parameters/EntriesSkip' - $ref: '#/components/parameters/EntriesIncludeLabels' - $ref: '#/components/parameters/PageLimit' responses: '200': description: Entry list content: application/json: schema: $ref: '#/components/schemas/EntryListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' post: tags: - Entries summary: Create an entry operationId: createEntry description: | Submits one entry keyed by field api_code (or api_code_alias). Unknown keys are ignored; when no valid key remains, returns 400, with `error_description` starting with `Entry attributes cannot be empty` and naming each dropped key (not a field of this form, or a signature / calculated field that cannot be written). - The form's field display rules and field validation still apply; a validation failure returns 400, and `error_description` is `{ "": ["error"] }` serialized as a JSON string. - Mobile fields skip SMS verification; signature fields and calculated fields cannot be written. - Returns 403 when the form's entry count has reached the plan limit. - Attachment fields accept several forms of input; see `EntryInput`. OAuth scope: write_entries requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryInput' example: field_1: 张三 field_2: '13800000000' field_3: - 选项 A - 选项 B field_4: '2024-05-01' responses: '201': description: Created; returns the entry content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/EntryValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': description: The form's entry count has reached its limit (`Form has reached entries limit`), or the OAuth scope is insufficient content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/entries/count": parameters: - $ref: '#/components/parameters/FormToken' get: tags: - Entries summary: Count entries operationId: countEntries description: | Returns the number of entries matching the filters, without the entries themselves. `filters` / `keyword` are the same as for `GET /forms/{form_token}/entries`; with neither, returns the total entry count of the form. A cooperator counts only the entries visible to their role. OAuth scope: read_entries parameters: - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Entry count content: application/json: schema: $ref: '#/components/schemas/EntryCountResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/entries/aggregate": parameters: - $ref: '#/components/parameters/FormToken' get: tags: - Entries summary: Aggregate entries operationId: aggregateEntries description: | Aggregates whole columns on the server over the entries matching the filters (sum, average, count, percentiles, etc.), optionally grouped by 1 to 2 fields. The response size depends only on the number of metrics and groups, not on the amount of data. - `metrics` is required, 1 to 20 items; the functions each field takes are in the `analytics.agg_funcs` returned by `GET /forms/{form_token}?include_analytics=true`. - `dimensions` is optional, at most 2 items; only fields whose `analytics.groupable` is true (single-value choice fields and date fields) can be grouped by, and a date field must specify `bucket`. - Without `dimensions`, `rows` has a single row; when grouped, one row per group, at most `limit` groups; `row_count` is the total number of groups, and `truncated` is true when there are more. - `filters` / `keyword` are the same as for the entry list, but `creator_id`, `serial_number` and association field conditions are not supported (returns 400). - Returns 400 when a field does not exist or is not readable by the caller, or a function or grouping does not apply to the field, and says which fields / functions / groupings are available. OAuth scope: read_entries parameters: - $ref: '#/components/parameters/AggregateMetrics' - $ref: '#/components/parameters/AggregateDimensions' - $ref: '#/components/parameters/AggregateLimit' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Aggregation result content: application/json: schema: $ref: '#/components/schemas/EntryAggregateResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/entries/summary": parameters: - $ref: '#/components/parameters/FormToken' get: tags: - Entries summary: Summarize entries operationId: summarizeEntries description: | Reads an overall summary of the form's entries in one call: an overview (matching count, added today) plus the distribution or numeric statistics of each analysable field. The response is only a few KB, regardless of the amount of data. - Each field returns a uniform structure by `kind`: choice fields give each choice's count and share, matrix fields are grouped by question, numbers give min / max / sum / average, dates give earliest / latest, text gives the distinct count. - By default includes every analysable field (fields whose `analytics.summarisable` is true, plus `created_at`), at most 60; fields beyond that are listed in `omitted_fields`, and `truncated` is true. - Returns 400 when a field named in `fields` is not analysable or not readable by the caller. - `filters` / `keyword` are the same as for the entry list, but `creator_id`, `serial_number` and association field conditions are not supported (returns 400). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/SummaryFields' - $ref: '#/components/parameters/SummaryIncludeOverview' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Entry summary content: application/json: schema: $ref: '#/components/schemas/EntrySummaryResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/views/{view_token}/entries/count": parameters: - $ref: '#/components/parameters/FormToken' - $ref: '#/components/parameters/ViewToken' get: tags: - Views summary: Count the entries of a view operationId: countFormViewEntries description: | Same as `GET /forms/{form_token}/entries/count`, but only over the entries the view's filters select: the view's filters apply first, and `filters` / `keyword` narrow the range further on top of them. The view's columns and sort do not affect the result; a view with no filters is the same as the whole form. Only views visible to the caller are accessible; otherwise 404 (View cannot be found). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Entry count content: application/json: schema: $ref: '#/components/schemas/EntryCountResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/views/{view_token}/entries/aggregate": parameters: - $ref: '#/components/parameters/FormToken' - $ref: '#/components/parameters/ViewToken' get: tags: - Views summary: Aggregate the entries of a view operationId: aggregateFormViewEntries description: | Same as `GET /forms/{form_token}/entries/aggregate`, but only over the entries the view's filters select: the view's filters apply first, and `filters` / `keyword` narrow the range further on top of them. The view's columns and sort do not affect the result; a view with no filters is the same as the whole form. Only views visible to the caller are accessible; otherwise 404 (View cannot be found). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/AggregateMetrics' - $ref: '#/components/parameters/AggregateDimensions' - $ref: '#/components/parameters/AggregateLimit' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Aggregation result content: application/json: schema: $ref: '#/components/schemas/EntryAggregateResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/views/{view_token}/entries/summary": parameters: - $ref: '#/components/parameters/FormToken' - $ref: '#/components/parameters/ViewToken' get: tags: - Views summary: Summarize the entries of a view operationId: summarizeFormViewEntries description: | Same as `GET /forms/{form_token}/entries/summary`, but only over the entries the view's filters select: the view's filters apply first, and `filters` / `keyword` narrow the range further on top of them. The view's columns and sort do not affect the result; a view with no filters is the same as the whole form. Only views visible to the caller are accessible; otherwise 404 (View cannot be found). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/SummaryFields' - $ref: '#/components/parameters/SummaryIncludeOverview' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Entry summary content: application/json: schema: $ref: '#/components/schemas/EntrySummaryResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/entries/batch": parameters: - $ref: '#/components/parameters/FormToken' post: tags: - Entries summary: Create entries in batch operationId: createEntriesBatch description: | Submits up to 200 entries at a time. Each entry is validated on its own; valid ones are written in bulk, invalid ones are recorded in `errors` (`index` is the position in the request array). Returns 201 when at least one succeeds and 422 when all fail; returns 400 when `entries` is empty or has over 200 entries. Before writing, the entry count limit is checked against the number of entries submitted; over the limit returns 403. A batch write does not trigger the callbacks of a single create, but creates one "import" activity record and backfills calculated fields. OAuth scope: write_entries requestBody: required: true content: application/json: schema: type: object required: - entries properties: entries: type: array minItems: 1 maxItems: 200 items: $ref: '#/components/schemas/EntryInput' additionalProperties: false responses: '201': description: At least one entry created content: application/json: schema: $ref: '#/components/schemas/BatchCreateResult' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': description: The form's entry count has reached its limit, or the OAuth scope is insufficient content: application/json: schema: $ref: '#/components/schemas/Error' '404': $ref: '#/components/responses/NotFound' '422': description: All entries failed to be created content: application/json: schema: $ref: '#/components/schemas/BatchCreateResult' '429': $ref: '#/components/responses/TooManyRequests' patch: tags: - Entries summary: Update entries in batch operationId: patchEntriesBatch description: | Partially updates entries in batch by serial number, up to 200 rows at a time. Each row requires `serial_number`; `entry` holds the fields to change (fields not mentioned stay unchanged). Each row is validated on its own; failed rows are recorded in `failed_rows` (`reason` is `invalid_serial_number` / `invalid_attributes`, etc.). Returns 200 when at least one row succeeds and 422 when all fail; returns 400 when `entries` is empty or has over 200 rows. Batch update does not handle the attachment lifecycle, so it **cannot write attachment fields** (including attachment columns inside table fields); update those one entry at a time. OAuth scope: write_entries requestBody: required: true content: application/json: schema: type: object required: - entries properties: entries: type: array minItems: 1 maxItems: 200 items: type: object required: - serial_number - entry properties: serial_number: type: integer description: Serial number of the entry to update entry: $ref: '#/components/schemas/EntryInput' additionalProperties: false additionalProperties: false responses: '200': description: At least one row updated content: application/json: schema: $ref: '#/components/schemas/BatchPatchResult' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: All rows failed to update content: application/json: schema: $ref: '#/components/schemas/BatchPatchResult' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/entries/{serial_number}": parameters: - $ref: '#/components/parameters/FormToken' - $ref: '#/components/parameters/SerialNumber' get: tags: - Entries summary: Show an entry operationId: getEntry description: | Returns one entry by serial number. `fields` limits the fields returned. OAuth scope: read_entries parameters: - $ref: '#/components/parameters/EntriesFields' - $ref: '#/components/parameters/EntriesIncludeLabels' responses: '200': description: One entry content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' put: tags: - Entries summary: Replace an entry operationId: replaceEntry description: | **Full replace**: writable fields absent from the request body are cleared, and only the values submitted in this request are kept. For a partial update use `PATCH`. Returns 400 when validation fails, with `error_description` being the JSON string of the field errors. OAuth scope: write_entries requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryInput' responses: '200': description: Updated; returns the entry content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/EntryValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' patch: tags: - Entries summary: Partially update an entry operationId: updateEntry description: | **Partial update**: only the fields present in the request body change; the rest keep their values. An attachment field is replaced as a whole set: to keep existing files, send back the URLs or attachment ids you read along with the new ones. Returns 400 when validation fails, with `error_description` being the JSON string of the field errors. OAuth scope: write_entries requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryInput' responses: '200': description: Updated; returns the entry content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/EntryValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' delete: tags: - Entries summary: Delete an entry operationId: deleteEntry description: | Deletes one entry and records a delete activity. On success returns the serial number of the deleted entry; returns 400 when deletion fails (for example, the form's state does not allow it). OAuth scope: write_entries responses: '200': description: Deleted content: application/json: schema: type: object required: - serial_number properties: serial_number: type: integer '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' post: tags: - Entries summary: Partially update an entry (POST) operationId: updateEntryViaPost description: | A POST alias of `PATCH` on the same path, with the same partial-update semantics, for clients that cannot easily send PATCH. OAuth scope: write_entries requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryInput' responses: '200': description: Updated; returns the entry content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/EntryValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/entries/{serial_number}/comments": parameters: - $ref: '#/components/parameters/FormToken' - $ref: '#/components/parameters/SerialNumber' get: tags: - Comments summary: List an entry's comments description: 'Returns all comments on the entry, oldest first, with their creators, mentioned users and attachments. A caller who is a cooperator needs entry read permission on the form, and the entry must be within their data scope; otherwise returns 400. OAuth scope: read_entries' operationId: listEntryComments responses: '200': description: List of comments content: application/json: schema: type: object required: - count - data properties: count: type: integer description: Number of comments data: type: array items: $ref: '#/components/schemas/EntryComment' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' post: tags: - Comments summary: Comment on an entry description: 'Creates a comment on the entry, authored by the caller; content is stripped of leading and trailing whitespace. Returns 400 when content is empty or longer than 2000 characters. Mention a user in content with @[] (a 24-character hex user id); the mentioned user must be a cooperator on the form, otherwise returns 400 and no comment is created. parent_id makes the comment a reply; the parent comment must belong to the same entry, otherwise returns 400. This endpoint cannot attach files. A caller who is a cooperator needs entry read permission, and the entry must be within their data scope; otherwise returns 400. OAuth scope: read_entries' operationId: createEntryComment requestBody: required: true content: application/json: schema: allOf: - $ref: '#/components/schemas/EntryCommentInput' - type: object required: - content responses: '201': description: Created; returns the comment content: application/json: schema: $ref: '#/components/schemas/EntryComment' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/entries/{serial_number}/comments/{comment_id}": parameters: - $ref: '#/components/parameters/FormToken' - $ref: '#/components/parameters/SerialNumber' - name: comment_id in: path required: true description: Comment id schema: type: string patch: tags: - Comments summary: Update a comment on an entry description: 'Changes a comment''s content; PUT is accepted too. Only the comment''s author can edit it; not even a form admin can edit someone else''s comment; otherwise returns 400. content follows the same rules as on create (leading and trailing whitespace stripped, at most 2000 characters, mentioned users must be cooperators); the comment''s existing attachments stay unchanged. Returns 404 (comment cannot be found) when the comment does not belong to the entry. OAuth scope: read_entries' operationId: updateEntryComment requestBody: required: true content: application/json: schema: type: object required: - content properties: content: type: string maxLength: 2000 description: New comment content; may include @[] mentions additionalProperties: false responses: '200': description: Updated; returns the comment content: application/json: schema: $ref: '#/components/schemas/EntryComment' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' delete: tags: - Comments summary: Delete a comment on an entry description: 'Deletes a comment. The comment''s author, the form''s creator, or a cooperator with the admin role can delete it; any other cooperator gets 400. Returns 404 (comment cannot be found) for a comment that is already deleted or does not belong to the entry. OAuth scope: read_entries' operationId: deleteEntryComment responses: '200': description: Deleted content: application/json: schema: type: object required: - id properties: id: type: string description: Id of the deleted comment '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/setting": get: tags: - Form Settings summary: Show a form's settings description: | Returns the form's after-submission settings, collection rules (closing rules, fill frequency), access policy, WeChat restrictions and Webhook settings. OAuth scope: form_setting The `weixin` key is returned only when the form has a WeChat Official Account selected (selected_weixin_appid is present). operationId: getFormSetting parameters: - $ref: '#/components/parameters/FormToken' responses: '200': description: Form settings content: application/json: schema: $ref: '#/components/schemas/FormSetting' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: tags: - Form Settings summary: Update a form's settings description: | Partially updates the form's settings, writing only the keys present in the request; PUT is accepted too. OAuth scope: form_setting - `submission_region_limited` / `submission_regions` are a paid feature and read-only here; to write them, use `setting` on the "Edit a form" endpoint. - `manually_close_rule`, `by_time_range_close_rule`, `by_entries_close_rule` and `fill_frequency` are nested objects; the server creates or updates them as nested attributes. - Returns `{ "status": "ok" }` on success; returns 400 when model validation fails, with body `{ "errors": "...", "status": "failed" }` (not the common error shape). operationId: updateFormSetting parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormSettingInput' responses: '200': description: Saved content: application/json: schema: $ref: '#/components/schemas/FormSettingSaveOk' '400': $ref: '#/components/responses/FormSettingBadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/manually_close_rule": get: tags: - Form Settings summary: Show whether a form is manually closed description: | Returns whether the form has been manually closed for collection. Returns `{ "closed": false }` when no manual closing rule has ever been created. OAuth scope: form_setting operationId: getManuallyCloseRule parameters: - $ref: '#/components/parameters/FormToken' responses: '200': description: Manual closing rule content: application/json: schema: $ref: '#/components/schemas/ManuallyCloseRule' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: tags: - Form Settings summary: Open or close collection manually description: | Opens (true) or closes (false) the form for collection manually through `open`; PUT is accepted too. Creates the manual closing rule when none exists, updates it otherwise. When the manual closed state changes, the server deletes the form's other closing rules (by time, by entry count, etc.). OAuth scope: form_setting Returns 400 when the `open` parameter is missing (the response body depends on the server implementation); returns 400 when saving fails, with body `{ "errors": "...", "status": "failed" }`. operationId: updateManuallyCloseRule parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormManuallyCloseRuleInput' responses: '200': description: The manual closing rule after the update content: application/json: schema: $ref: '#/components/schemas/ManuallyCloseRule' '400': $ref: '#/components/responses/FormSettingBadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/access_policy": patch: tags: - Form Settings summary: Update the fill frequency limit description: | Updates the form's fill frequency limit (fill_frequency); PUT is accepted too. This endpoint takes only the `fill_frequency` key; for the other access policy keys, use PATCH /forms/{form_token}/setting. OAuth scope: form_setting Returns `{ "status": "ok" }` on success; returns 400 when validation fails, with body `{ "errors": "...", "status": "failed" }` (not the common error shape). operationId: updateAccessPolicy parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AccessPolicyInput' responses: '200': description: Saved content: application/json: schema: $ref: '#/components/schemas/FormSettingSaveOk' '400': $ref: '#/components/responses/FormSettingBadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/webhook": post: tags: - Form Settings summary: Set the Webhook description: | Sets the form's entry push URL `entry_post_url` and turns on pushing new entries (post_new_entry = true). OAuth scope: form_setting The plan must support Webhook; otherwise returns 402 with an empty body. The server does not check the save result and echoes `entry_post_url` from the settings as is (whether an invalid URL was persisted depends on the server implementation). operationId: createFormWebhook parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookInput' responses: '200': description: The current push URL content: application/json: schema: $ref: '#/components/schemas/FormWebhook' '401': $ref: '#/components/responses/Unauthorized' '402': description: The plan does not support API v1 access (returns error_description), or the plan does not support Webhook (empty body) content: application/json: schema: type: object properties: error_description: type: string '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' delete: tags: - Form Settings summary: Delete the Webhook description: | Removes `entry_post_url` from the form's settings. Returns 200 with an empty body on success. OAuth scope: form_setting operationId: deleteFormWebhook parameters: - $ref: '#/components/parameters/FormToken' responses: '200': description: Deleted; the body is empty '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/theme": patch: tags: - Form Settings summary: Update a form's theme description: | Partially updates the form's theme (colors, background, header image, typography, form container, submit button); PUT is accepted too. - The request body must contain at least one of primary_color / secondary_color / wallpaper / header / typography / form_container / submit_button (`generate_header_image` is turned into header.header_image_url, so it counts too); otherwise 400. - Header image source precedence: header_image_upload_token > header_image_base64 > header_image_url > header_image_attachment_id; when a header image is set and header.type is not given, header.type is set to image. - Background image source precedence: background_image_upload_token > background_image_url > background_image_attachment_id. Setting or removing the background image also removes the preset background image that comes with the theme template; the background color is kept. - `header_image_attachment_id` / `background_image_attachment_id` take the `attachment_id` returned by "Upload a form image" (image_type header / wallpaper); pass an empty string `""` to remove the current image. - `header.carousel_images` replaces the carousel images as a whole: at most 5, not empty; each item gives one of image_upload_token / image_url / attachment_id, and an attachment_id must be a carousel image the form already has; when it is passed and header.type is not given, header.type is set to carousel. - Keys in `text_style` and `typography.*` use underscores (e.g. font_size); the server converts them to hyphenated CSS keys and merges them into the existing styles; the response uses the hyphenated keys. - `generate_header_image` has AI generate a header image and consumes AI points; returns 402 when points are insufficient, 400 when generation fails. - An image upload_token is the `form_image_token` used by "Upload a form image"; the image purpose it records must match (header / wallpaper / carousel), and its upload must be complete. OAuth scope: form_setting operationId: updateFormTheme parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ThemeInput' responses: '200': description: The saved theme content: application/json: schema: $ref: '#/components/schemas/FormTheme' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/exam_setting": get: tags: - Form Settings summary: Show a form's exam settings description: | Returns an exam form's settings for what is shown after the exam is submitted, the time limit, the pre-exam notice and score range comments. Only for forms in the exam scene (scene = exam); otherwise returns 400. Returns an empty object `{}` when the form has no exam settings record yet. OAuth scope: form_setting operationId: getExamSetting parameters: - $ref: '#/components/parameters/FormToken' responses: '200': description: Exam settings (may be an empty object) content: application/json: schema: $ref: '#/components/schemas/ExamSetting' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: tags: - Form Settings summary: Update a form's exam settings description: | Partially updates an exam form's settings; PUT is accepted too. Only for exam-scene forms; otherwise returns 400. OAuth scope: form_setting - When the plan does not support "show the score after submission", `notice_after_filling_mode` is forced to none and `success_message_rich_text` is ignored. - `interval_comments` replaces the existing range comments as a whole; it takes effect only when `notice_after_filling_mode` (passed in this request or already saved) is grade / explaination / answer; passing an empty array does not turn range comments off. - Range comments must have end_point ≥ start_point and must not overlap; otherwise 400. - Passing `show_timeout: true` returns 400 when the form already has required questions; once the time limit is on, question fields cannot be made required (required candidate info fields are not affected); to turn on the time limit, make the questions optional first. - When `notice_after_filling_mode` is not none, the server clears success_redirect_url / success_redirect_fields in the form's settings. - A request body with no recognized keys is a no-op and returns the current settings. operationId: updateExamSetting parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ExamSettingInput' responses: '200': description: The saved exam settings content: application/json: schema: $ref: '#/components/schemas/ExamSetting' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/evaluation_setting": get: tags: - Form Settings summary: Show a form's evaluation settings description: | Returns an evaluation form's report display, dimension (indicator) settings and total score range comments. Only for forms in the evaluation scene (scene = evaluation); otherwise returns 400. Returns an empty object `{}` when the form has no evaluation settings record yet. OAuth scope: form_setting operationId: getEvaluationSetting parameters: - $ref: '#/components/parameters/FormToken' responses: '200': description: Evaluation settings (may be an empty object) content: application/json: schema: $ref: '#/components/schemas/EvaluationSetting' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: tags: - Form Settings summary: Update a form's evaluation settings description: | Partially updates an evaluation form's settings; PUT is accepted too. Only for evaluation-scene forms; otherwise returns 400. OAuth scope: form_setting - When the plan does not support "show the evaluation report after submission", `notice_after_filling_mode` is forced to none. - `evaluation_comments` replaces the total score range comments as a whole, and an empty array turns range comments off; it takes effect only when `notice_after_filling_mode` (passed in this request or already saved) is reports / customize. - A comment by score range must give both start_point and end_point; comments written with conditions in the form editor read back as `id` + `conditions` and must be passed back with their original id when updating (only comment / retry may change; the conditions cannot be changed and no range can be added); leaving one out or changing it returns 400. - `indicator_setting.indicators` replaces the dimensions as a whole; pass `api_code` back to keep an existing dimension's identity. A dimension can bind only scorable questions visible on the form, referenced by `field_api_codes` or `field_cids`; referencing an unknown field returns 400. - When `notice_after_filling_mode` is not none, the server clears success_redirect_url / success_redirect_fields in the form's settings. - A request body with no recognized keys is a no-op and returns the current settings. operationId: updateEvaluationSetting parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EvaluationSettingInput' responses: '200': description: The saved evaluation settings content: application/json: schema: $ref: '#/components/schemas/EvaluationSetting' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/field_rules": get: tags: - Forms summary: Show a form's field display rules description: | Returns the form's effective field display rules (logic jumps). `index` is the 0-based position; field_rules updates and removals in PATCH /forms/{form_token} locate rules by this index. OAuth scope: forms operationId: listFieldRules parameters: - $ref: '#/components/parameters/FormToken' responses: '200': description: List of field display rules content: application/json: schema: type: object required: - count - data properties: count: type: integer description: Number of rules data: type: array items: $ref: '#/components/schemas/FieldRule' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/extended_attributes": get: tags: - Forms summary: List the source-tracking links description: | Returns the "track entry source" extended attributes generated for the form (oldest first), each with the fill link that carries its value. OAuth scope: forms operationId: listExtendedAttributes parameters: - $ref: '#/components/parameters/FormToken' responses: '200': description: List of extended attributes content: application/json: schema: type: object required: - count - data properties: count: type: integer data: type: array items: $ref: '#/components/schemas/ExtendedAttribute' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/cooperators": get: tags: - Forms summary: List a form's cooperators description: | Returns the form's cooperators and their role names, including roles inherited from folders; when a user gets roles through several paths, only the nearest one is returned. OAuth scope: forms operationId: listFormCooperators parameters: - $ref: '#/components/parameters/FormToken' responses: '200': description: List of cooperators content: application/json: schema: type: object required: - count - data properties: count: type: integer data: type: array items: $ref: '#/components/schemas/Cooperator' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/copy": post: tags: - Forms summary: Copy a form description: | Copies the form and returns the new form (same shape as GET /forms/{form_token}). The new form's creator is the calling user (the account owner for an account token). OAuth scope: forms - When the source form allows public copying (can_duplicated_in_public), the caller needs no access to the source form; otherwise a caller without access gets 404. - Returns 403 when the source form is frozen or its creator's account is disabled, with body `{ "errors": ..., "status_code": "form_forbidden" }` (not the common error shape). - `folder_token` takes a folder token or id; returns 404 when the folder does not exist or the caller lacks manage permission on it. - Returns 400 when copying fails (model validation does not pass). operationId: copyForm parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/CopyFormInput' responses: '200': description: The new form content: application/json: schema: $ref: '#/components/schemas/Form' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': description: Insufficient OAuth scope (error_description shape), or the source form or its creator is frozen (errors + status_code shape) content: application/json: schema: oneOf: - type: object required: - error_description properties: error_description: type: string - $ref: '#/components/schemas/FormFrozenError' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/folder": patch: tags: - Forms summary: Move a form into a folder description: | Moves the form into a folder, or out of one (pass null as `folder_token`); PUT is accepted too. The move affects only the calling user's folder placement. OAuth scope: forms - The request body must contain the `folder_token` key (its value may be null); otherwise 400. - `folder_token` takes only a folder token (not an id); returns 404 when the folder does not exist or the current user lacks manage permission on it. - The folder type (form / table) must match the form's type; otherwise 400. - To move a table, use `PATCH /tables/{table_token}/folder`. operationId: moveFormToFolder parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormFolderMoveInput' responses: '200': description: Move result content: application/json: schema: $ref: '#/components/schemas/FormFolderMoveResult' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/weixin_oauth_session": post: tags: - Forms summary: Exchange a WeChat authorization code for an openid description: | Exchanges the `code` returned by WeChat web authorization for the user's openid, through the WeChat Official Account the form has selected. When the form's WeChat authorization scope is userinfo, also returns `unionid` (when WeChat returns one) and `profile`. OAuth scope: write_entries - Returns 400 when the form has no WeChat Official Account configured or that account does not exist; returns 400 when `code` is missing. - Returns 502 when the exchange fails on the WeChat side (invalid code, etc.) or fetching the user info fails. operationId: createWeixinOauthSession parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormWeixinOauthSessionInput' responses: '200': description: Authorization result content: application/json: schema: $ref: '#/components/schemas/FormWeixinOauthSession' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '502': description: The WeChat OAuth or user info call failed content: application/json: schema: type: object required: - error_description properties: error_description: type: string description: The errmsg returned by WeChat, or "WeChat OAuth failed" / "WeChat userinfo failed" "/forms/{form_token}/views": get: tags: - Views summary: List a form's views description: 'Returns the views the caller can see on the form: views they created, and views whose visibility other cooperators set to cooperators; other users'' personal views are not returned. The order follows the caller''s own saved view order; views not in it are appended by position, then created_at. OAuth scope: forms' operationId: listFormViews parameters: - $ref: '#/components/parameters/FormToken' responses: '200': description: List of views content: application/json: schema: type: object required: - count - data properties: count: type: integer description: Number of views returned data: type: array items: $ref: '#/components/schemas/FormView' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' post: tags: - Views summary: Create a view on a form description: 'Creates a new view on the form, created by the caller; visibility defaults to cooperators when not passed, and position is the highest position among the currently visible views plus 1. Each user can have at most 100 views on one form; at the limit, returns 422 (View limit reached). When view_type is kanban and kanban_group_by_api_code is not passed, the server picks the grouping field; when kanban_hidden_groups is not passed, the __unset__ group is hidden by default; when prefer_columns is empty, the form''s default columns are used (at most 5 columns for a kanban view, serial_number included). Returns 422 when filter is invalid (not an array, unknown field, unsupported operator, invalid value). Returns 422 when model validation fails (e.g. name is empty or longer than 120 characters, or the grouping field does not support kanban grouping). Form views (view_type form): supported only on tables, otherwise 422; title defaults to the table name; without field_overrides, all fillable columns are selected in the current column order; published defaults to false (the fill link does not work while unpublished). title / description / published / field_overrides apply only to form views; using them on another type returns 422. Creating, updating or deleting a form view (including switching a view to or from a form view) requires the caller to hold a predefined role on the table that can add entries, otherwise 403; an account token is exempt. Returns 422 when a fill item''s column does not exist, cannot be a fill item, or sets a validation its column type does not support; the error message names the column''s api_code. OAuth scope: forms' operationId: createFormView parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: allOf: - $ref: '#/components/schemas/FormViewInput' - type: object required: - name responses: '201': description: Created; returns the view content: application/json: schema: $ref: '#/components/schemas/FormView' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: The request cannot be processed (view limit reached, invalid filters, model validation failure, deletion not allowed, etc.); the body is { error_description } content: application/json: schema: $ref: '#/components/schemas/ViewUnprocessableError' "/forms/{form_token}/views/{view_token}": parameters: - $ref: '#/components/parameters/FormToken' - name: view_token in: path required: true description: View token schema: type: string get: tags: - Views summary: Show a view of a form description: 'Returns one view. Only views visible to the caller can be read (created by the caller or visible to cooperators); another user''s personal view returns 404 (View cannot be found). OAuth scope: forms' operationId: getFormView responses: '200': description: View details content: application/json: schema: $ref: '#/components/schemas/FormView' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: tags: - Views summary: Update a view of a form description: 'Updates the view''s configuration; PUT is accepted too. Only the keys present in the request are updated: an empty array for filter clears the filters, and leaving filter out keeps them unchanged; when kanban_group_by_api_code changes and kanban_group_order / kanban_hidden_groups are not passed with it, those two lists reset to their defaults. Cooperators can change the configuration of a view visible to cooperators, but only the view''s creator can switch visibility, otherwise returns 403; a view whose view_scope is form cannot switch visibility. Returns 422 when filter is invalid or model validation fails. field_overrides replaces the fill item settings as a whole; form views have the same permission requirements and parameter limits as on create. OAuth scope: forms' operationId: updateFormView requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormViewInput' responses: '200': description: Updated; returns the view content: application/json: schema: $ref: '#/components/schemas/FormView' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: The request cannot be processed (view limit reached, invalid filters, model validation failure, deletion not allowed, etc.); the body is { error_description } content: application/json: schema: $ref: '#/components/schemas/ViewUnprocessableError' delete: tags: - Views summary: Delete a view of a form description: 'Deletes a view. Predefined views (predefined) and views whose view_scope is form cannot be deleted, and the deletion is also refused when it would leave the caller with no visible view; all of these return 422. Deleting a form view needs the same permission as creating one (otherwise 403); once it is deleted, its fill link stops working immediately, and this cannot be undone. OAuth scope: forms' operationId: deleteFormView responses: '200': description: Deleted content: application/json: schema: type: object required: - token properties: token: type: string description: Token of the deleted view '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: The request cannot be processed (view limit reached, invalid filters, model validation failure, deletion not allowed, etc.); the body is { error_description } content: application/json: schema: $ref: '#/components/schemas/ViewUnprocessableError' "/forms/{form_token}/views/{view_token}/entries": get: tags: - Views summary: List a view's entries description: 'Returns the form''s entries under the view''s filters and sort rules, at most 50 per page. The returned fields are limited to those in the view''s prefer_columns (serial_number always included); when prefer_columns is empty, all pushable fields are returned. Sorting follows the view''s sort rules, with serial_number ascending appended when they do not include serial_number. Paginate with the next parameter (a row offset); next is null on the last page. Returns 400 when the view''s filters use an operator the query engine does not support. Only views visible to the caller are accessible, otherwise 404 (View cannot be found). OAuth scope: read_entries' operationId: listFormViewEntries parameters: - $ref: '#/components/parameters/FormToken' - name: view_token in: path required: true description: View token schema: type: string - name: next in: query required: false description: The next value from the previous page's response (a row offset, starting at 0); a negative value is treated as 0 schema: type: integer minimum: 0 - $ref: '#/components/parameters/EntriesIncludeLabels' responses: '200': description: Entry list content: application/json: schema: $ref: '#/components/schemas/EntryListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/forms/{form_token}/entry_attachments": post: tags: - Uploads summary: Upload an entry attachment operationId: uploadEntryAttachment security: - {} - bearerAuth: [] description: | Uploads a file ahead of time for a form's attachment field (or an attachment column in a table field) and returns the attachment ID; then, when creating / updating an entry, put that ID (or the upload token) into the matching field to bind it. An uploaded attachment that no entry references stays unused. Authenticate in one of two ways: 1. Regular API credentials (a Bearer token). 2. A one-time upload token `attachment_token` (instead of regular credentials): the token starts with `entry_att_tok_`, is valid for 30 minutes, can be used only once, and is bound to the form, field, column and file metadata. When the request carries `attachment_token`, regular credentials are not checked and the request acts as the token's user; returns 400 `attachment_token is invalid or expired; prepare upload again` when the token is invalid, expired, already used, its user has been deleted, or it does not match the requested form / field / column; also returns 400 when the uploaded file's name, Content-Type or byte size does not match the token. Returns 401 when there are neither credentials nor `attachment_token`. Send the file content in one of two ways: the `file` field of `multipart/form-data`; or a Base64 string in the `base64` (or `data`) field of a JSON / form-encoded body (a `data:;base64,` prefix is allowed), with `file_name` (or `filename`) and `content_type`. Base64 content cannot exceed 5 MB once decoded; larger returns 400 `attachment exceeds 5MB limit`, and a decoding failure returns 400 `base64 is invalid`; returns 400 `file or base64 is required` when neither is given. `field_api_code` must point to an attachment field or a table field; for a table field, `dimension_api_code` must also be passed and point to an attachment column in that table field, otherwise returns 400; returns 404 when the field or column does not exist. The file size is capped by the per-file limit set on the field (or column); a larger file returns 422, with the specific validation message in `error_description` (e.g. `文件超过了10 MB`); returns 422 `上传失败,请重试` when uploading to object storage fails (the server's wording is authoritative). Returns 404 `form cannot be found` when the form does not exist or is not accessible to the current identity. OAuth scope: write_entries parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: multipart/form-data: schema: type: object required: - field_api_code properties: field_api_code: type: string description: api_code of the attachment field; for an attachment column in a table field, pass the table field's api_code dimension_api_code: type: string description: api_code of the attachment column in a table field; required when `field_api_code` is a table field attachment_token: type: string description: One-time upload token, starting with `entry_att_tok_`; when passed, it replaces the regular credentials file: type: string description: The file to upload; pass either this or `base64` contentMediaType: application/octet-stream base64: type: string description: The file content as a Base64 string, optionally with a data URI prefix; pass either this or `file` data: type: string description: Alias of `base64` file_name: type: string description: File name for a Base64 upload; defaults to `attachment` filename: type: string description: Alias of `file_name` content_type: type: string description: MIME type for a Base64 upload; defaults to the one in the data URI prefix, otherwise `application/octet-stream` additionalProperties: false application/json: schema: $ref: '#/components/schemas/EntryAttachmentBase64Input' responses: '201': description: Uploaded content: application/json: schema: $ref: '#/components/schemas/UploadedEntryAttachment' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: The attachment failed validation (for example, it exceeds the field's per-file size limit) or could not be stored content: application/json: schema: type: object required: - error_description properties: error_description: type: string description: Why validation failed "/forms/{form_token}/import_files": post: tags: - Uploads summary: Upload an import file operationId: uploadImportFile security: - {} - bearerAuth: [] description: | Uploads a spreadsheet file (`.xlsx` / `.xls` / `.csv`) for bulk-importing entries into the given form, and returns the import attachment ID; then pass it as `attachment_id` to "Import entries from an uploaded spreadsheet" (`POST /forms/{form_token}/entry_imports`) to start the import. Authenticate in one of two ways: 1. Regular API credentials (a Bearer token). 2. A one-time upload token `import_file_token` (instead of regular credentials): the token starts with `import_file_tok_`, is valid for 30 minutes, can be used only once, and is bound to the form and the file metadata. When the request carries `import_file_token`, regular credentials are not checked, and the request acts as the user the token belongs to; the uploaded file's original file name, Content-Type and byte size must match what the token recorded, otherwise returns 400. Returns 400 `import_file_token is invalid or expired; prepare upload again` when the token does not exist, has expired, has been used, or its user has been deleted; returns 400 `import_file_token was issued for another form; prepare upload again` when the token belongs to another form. Returns 401 when there are neither credentials nor an `import_file_token`. The request must be `multipart/form-data`, with the file in the `file` field; a missing file returns 400 `file is required`. The file size is capped by the plan's Excel import limit (in MB), and the extension must be xls / xlsx / csv; otherwise returns 422, with the validation details in `error_description` (with an upload token, the token stays usable, so the file can be uploaded again). Returns 404 `form cannot be found` when the form does not exist or is not accessible to the current caller. OAuth scope: write_entries parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: multipart/form-data: schema: type: object required: - file properties: import_file_token: type: string description: One-time upload token, starting with `import_file_tok_`; when passed, it replaces the regular credentials file: type: string description: The xlsx / xls / csv file to import; with an upload token, its file name, Content-Type and size must match what the token recorded contentMediaType: application/octet-stream additionalProperties: false responses: '201': description: Uploaded content: application/json: schema: $ref: '#/components/schemas/UploadedImportFile' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: The file failed validation (it exceeds the plan's import limit, or its extension is not supported) content: application/json: schema: type: object required: - error_description properties: error_description: type: string description: Why validation failed "/forms/{form_token}/entry_imports": post: tags: - Entries summary: Import entries from an uploaded spreadsheet operationId: createEntryImport description: | Appends each row of a spreadsheet uploaded with "Upload an import file" as an entry of this form. Upload the file first to get the import attachment ID (`attachment_id`), then say here which column goes into which field. Problems that can be detected up front, such as the file, the plan's import limit, the header row and the column mapping, are checked before the job is created; a rejected import writes no entries. Error messages include the spreadsheet's actual layout (row and column range, and the header contents), so the request can be fixed and retried. Once validation passes, returns `201` and the entries are written in the background: `201` means the job has started, not finished; poll "Show an entry import job" for the result. - `attachment_id` must be an import file the current user uploaded for this form, otherwise returns 400 (the file cannot be found; upload it again); returns 400 when the file is not xls / xlsx / csv or cannot be read. - `columns` must not be empty; each item names the target field with `field_api_code`, and the source column with `column_label` (the header text, which must exactly match the header cell after trimming leading and trailing spaces) or `sheet_column_index` (the column number); when both are given, `sheet_column_index` wins. - The field must be one this form can import into; one field cannot map to several columns; when several header columns share a name, use `sheet_column_index` instead; the column number must be within the spreadsheet's column range. - `header_row_index` defaults to the first row of the spreadsheet, and there must be data rows below it. - Every required field of the form must have a column, otherwise returns 400 listing the missing fields. - `unique_field_code` names a field to deduplicate on: when a row's value for that field already exists in the form's entries, the row is skipped (counted in `skip_count`). - Returns 404 `form cannot be found` when the form does not exist or is not accessible to the current caller. OAuth scope: write_entries parameters: - $ref: '#/components/parameters/FormToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryImportInput' responses: '201': description: Import job created; entries are written in the background content: application/json: schema: $ref: '#/components/schemas/EntryImportCreated' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/forms/{form_token}/entry_imports/{id}": get: tags: - Entries summary: Show an entry import job operationId: getEntryImport description: | Returns the progress and result of an entry import job. While `status` is `pending` / `running`, the job is still in progress, and `processed_rows` and `total_rows` can be used to show progress; `success` / `failed` / `cancelled` are final states; `imported_count` / `skip_count` / `invalid_count` are the numbers of rows written, skipped and failing validation, `warnings` holds per-row notices, and `error_message` is why the job failed. A job can be read only through the form it imports into: when the id does not exist, is not a valid id, or belongs to another form, returns 404 `Import job not found for this form — check the id, and that it belongs to this form.`. Returns 404 `form cannot be found` when the form does not exist or is not accessible to the current caller. OAuth scope: write_entries parameters: - $ref: '#/components/parameters/FormToken' - $ref: '#/components/parameters/EntryImportId' responses: '200': description: Import job content: application/json: schema: $ref: '#/components/schemas/EntryImportJob' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/form_image_attachments": post: tags: - Uploads summary: Upload a form image operationId: uploadFormImage security: - {} - bearerAuth: [] description: | Uploads an image that belongs to the form itself (a picture choice image, a header image, a background image, one frame of the header carousel, the header image of the form's public query page, or an inline image in the form description / a field description), and returns the image attachment ID. The image is not bound to any form yet; it takes effect only when a form or theme references it later. Authenticate in one of two ways: 1. Regular API credentials (a Bearer token). `image_type` must then say what the image is for, and can only be `header` (header image), `wallpaper` (background image), `opensearch_header` (public query page header image) or `description` (inline description image): pass the returned `attachment_id` to `header.header_image_attachment_id` / `wallpaper.background_image_attachment_id` of "Update a form's theme", or to `header.background_image.attachment_id` of "Update a public query"; `description` also returns the image address `url`, which goes into the `` of the form `description` or of a field's `notes`. When the form is saved, the image belongs to that form (at most 30 per form); images not used by any form within 7 days are cleaned up. Returns 400 `image_type must be one of: field_choice, header, wallpaper, carousel, opensearch_header, description.` when `image_type` is missing or not one of `field_choice` / `header` / `wallpaper` / `carousel` / `opensearch_header` / `description`; `field_choice` / `carousel` have nowhere that accepts an attachment ID, so they can only be uploaded with an upload token, otherwise returns 400. 2. A one-time upload token `form_image_token` (instead of regular credentials): the token starts with `form_img_tok_`, is valid for 30 minutes, can be used only once, and has already recorded the image purpose (`field_choice` / `header` / `wallpaper` / `carousel` / `opensearch_header` / `description`; `image_type` is then ignored) and the file metadata; the uploaded file's original file name, Content-Type and byte size must match what the token recorded, otherwise returns 400. After a successful upload, do not use the returned `attachment_id` directly; instead reference the same token in a choice's `image_upload_token` in "Create a form" / "Edit a form", in `header.header_image_upload_token` / `wallpaper.background_image_upload_token` / `header.carousel_images[].image_upload_token` of "Update a form's theme", or in `header.background_image.image_upload_token` of "Update a public query"; for the `description` purpose nothing references the token, so use the returned `url` directly. Returns 400 `form_image_token is invalid or expired; prepare upload again` when the token does not exist, has expired, has been used, or its user has been deleted. Returns 401 when there are neither credentials nor a `form_image_token`. The request must be `multipart/form-data`, with the image binary in the `file` field; a missing file returns 400 `file is required`. OAuth scope: forms when `image_type` (or the purpose the token recorded) is field_choice, opensearch_header or description; form_setting otherwise requestBody: required: true content: multipart/form-data: schema: type: object required: - file properties: image_type: type: string enum: - field_choice - header - wallpaper - carousel - opensearch_header - description description: What the image is for; without an upload token it is required and can only be header / wallpaper / opensearch_header / description; ignored with an upload token form_image_token: type: string description: One-time upload token, starting with `form_img_tok_`; when passed, it replaces the regular credentials file: type: string description: The image file; with an upload token, its file name, Content-Type and size must match what the token recorded contentMediaType: application/octet-stream additionalProperties: false responses: '201': description: Uploaded content: application/json: schema: $ref: '#/components/schemas/UploadedFormImage' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/tables": get: tags: - Tables summary: List tables operationId: listTables description: | Returns the tables (`kind=table`) visible to the current caller. Pagination, `q`, `filters`, `sort`, `next`, `skip` and `limit` mean the same as in the form list; 50 per page by default, up to 1000. OAuth scope: forms parameters: - $ref: '#/components/parameters/FormsQ' - $ref: '#/components/parameters/FormsFilters' - $ref: '#/components/parameters/FormsSort' - $ref: '#/components/parameters/FormsNext' - $ref: '#/components/parameters/FormsSkip' - $ref: '#/components/parameters/PageLimit' responses: '200': description: Table list content: application/json: schema: $ref: '#/components/schemas/TableListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' post: tags: - Tables summary: Create a table operationId: createTable description: | Creates a table. Same as creating a form, except: - field types can only be the column types tables support: `TextArea`, `RadioButton`, `CheckBox`, `BooleanField`, `MobileField`, `NumberField`, `DateTimeField`, `EmailField`, `LinkField`, `AttachmentField`, `FormulaField`, `RelationField`; - attachment columns do not accept limit properties such as count / size limits, and number / formula columns have limited precision; a violation returns 400 listing the offending columns; - choice columns do not get an "Other" choice; `folder_token` must be a table folder; `layout` is not supported. - with `with_default_entries: true`, 3 blank entries are added after creation (as when creating a table in the product); by default none are added. Returns the table structure, including fields and views. OAuth scope: forms requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TableCreateInput' responses: '201': description: Created content: application/json: schema: $ref: '#/components/schemas/Table' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': description: The folder named by folder_token does not exist or cannot be managed content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}": parameters: - $ref: '#/components/parameters/TableToken' get: tags: - Tables summary: Show a table's structure operationId: getTable description: | Returns the table's basic information, field definitions and the views visible to the current caller. Returns 404 `table cannot be found` when the token is not a table (for example, a regular form). OAuth scope: forms responses: '200': description: Table structure content: application/json: schema: $ref: '#/components/schemas/Table' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' parameters: - name: include_analytics in: query required: false description: Whether to include `analytics` on each analysable field (the aggregate functions available, whether it can be grouped by, the shape of its summary). Defaults to false. schema: type: boolean default: false patch: tags: - Tables summary: Edit a table operationId: updateTable description: | Edits a table incrementally; `PUT` is also accepted. The request body is the same as for editing a form (`kind` is ignored); attachment columns in `fields.add` and `fields.update` do not accept limit properties, and types in `fields.add` must be column types tables support. OAuth scope: forms requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormUpdateInput' responses: '200': description: Updated content: application/json: schema: $ref: '#/components/schemas/Table' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' delete: tags: - Tables summary: Delete a table operationId: deleteTable description: | Deletes a table and its entries; on success, returns the table token. OAuth scope: forms responses: '200': description: Deleted content: application/json: schema: type: object required: - token properties: token: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/fields/check": get: tags: - Tables summary: Check whether table columns already hold data description: | Same as GET /forms/{form_token}/fields/check, applied to the columns of a table. Returns 404 (`table cannot be found`) when `table_token` does not point to a table. OAuth scope: forms operationId: checkTableFieldData parameters: - $ref: '#/components/parameters/TableToken' - $ref: '#/components/parameters/FieldDataChecks' responses: '200': description: Per-item check results content: application/json: schema: $ref: '#/components/schemas/FieldDataCheckResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/fields/preview_convert": get: tags: - Tables summary: Preview a table column type change description: | Same as GET /forms/{form_token}/fields/preview_convert, applied to the columns of a table; `target_type` accepts only column types tables support (see `GET /field_types?kind=table`). Returns 404 (`table cannot be found`) when `table_token` does not point to a table. OAuth scope: forms operationId: previewTableFieldTypeChange parameters: - $ref: '#/components/parameters/TableToken' - $ref: '#/components/parameters/FieldTypeChangeChecks' responses: '200': description: Per-item preview results content: application/json: schema: $ref: '#/components/schemas/FieldTypeChangePreviewResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/entries": parameters: - $ref: '#/components/parameters/TableToken' get: tags: - Tables summary: List table entries operationId: listTableEntries description: | Exactly the same as `GET /forms/{form_token}/entries`, except that the target must be a table (otherwise 404 `table cannot be found`). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/EntriesFields' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' - $ref: '#/components/parameters/EntriesSort' - $ref: '#/components/parameters/EntriesCreatedAt' - $ref: '#/components/parameters/EntriesNext' - $ref: '#/components/parameters/EntriesSkip' - $ref: '#/components/parameters/EntriesIncludeLabels' - $ref: '#/components/parameters/PageLimit' responses: '200': description: Entry list content: application/json: schema: $ref: '#/components/schemas/EntryListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' post: tags: - Tables summary: Create a table entry operationId: createTableEntry description: | Same as `POST /forms/{form_token}/entries`. OAuth scope: write_entries requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryInput' responses: '201': description: Created content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/EntryValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/entries/count": parameters: - $ref: '#/components/parameters/TableToken' get: tags: - Tables summary: Count table entries operationId: countTableEntries description: | Exactly the same as `GET /forms/{form_token}/entries/count`, except that the target must be a table (otherwise 404 `table cannot be found`). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Entry count content: application/json: schema: $ref: '#/components/schemas/EntryCountResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/entries/aggregate": parameters: - $ref: '#/components/parameters/TableToken' get: tags: - Tables summary: Aggregate table entries operationId: aggregateTableEntries description: | Exactly the same as `GET /forms/{form_token}/entries/aggregate`, except that the target must be a table (otherwise 404 `table cannot be found`). For the functions and groupings each field supports, see `GET /tables/{table_token}?include_analytics=true`. OAuth scope: read_entries parameters: - $ref: '#/components/parameters/AggregateMetrics' - $ref: '#/components/parameters/AggregateDimensions' - $ref: '#/components/parameters/AggregateLimit' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Aggregation result content: application/json: schema: $ref: '#/components/schemas/EntryAggregateResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/entries/summary": parameters: - $ref: '#/components/parameters/TableToken' get: tags: - Tables summary: Summarize table entries operationId: summarizeTableEntries description: | Exactly the same as `GET /forms/{form_token}/entries/summary`, except that the target must be a table (otherwise 404 `table cannot be found`). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/SummaryFields' - $ref: '#/components/parameters/SummaryIncludeOverview' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Entry summary content: application/json: schema: $ref: '#/components/schemas/EntrySummaryResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/views/{view_token}/entries/count": parameters: - $ref: '#/components/parameters/TableToken' - $ref: '#/components/parameters/ViewToken' get: tags: - Tables summary: Count the entries of a view operationId: countTableViewEntries description: | Exactly the same as `GET /forms/{form_token}/views/{view_token}/entries/count`, except that the target must be a table (otherwise 404 `table cannot be found`). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Entry count content: application/json: schema: $ref: '#/components/schemas/EntryCountResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/views/{view_token}/entries/aggregate": parameters: - $ref: '#/components/parameters/TableToken' - $ref: '#/components/parameters/ViewToken' get: tags: - Tables summary: Aggregate the entries of a view operationId: aggregateTableViewEntries description: | Exactly the same as `GET /forms/{form_token}/views/{view_token}/entries/aggregate`, except that the target must be a table (otherwise 404 `table cannot be found`). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/AggregateMetrics' - $ref: '#/components/parameters/AggregateDimensions' - $ref: '#/components/parameters/AggregateLimit' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Aggregation result content: application/json: schema: $ref: '#/components/schemas/EntryAggregateResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/views/{view_token}/entries/summary": parameters: - $ref: '#/components/parameters/TableToken' - $ref: '#/components/parameters/ViewToken' get: tags: - Tables summary: Summarize the entries of a view operationId: summarizeTableViewEntries description: | Exactly the same as `GET /forms/{form_token}/views/{view_token}/entries/summary`, except that the target must be a table (otherwise 404 `table cannot be found`). OAuth scope: read_entries parameters: - $ref: '#/components/parameters/SummaryFields' - $ref: '#/components/parameters/SummaryIncludeOverview' - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' responses: '200': description: Entry summary content: application/json: schema: $ref: '#/components/schemas/EntrySummaryResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/entries/{serial_number}": parameters: - $ref: '#/components/parameters/TableToken' - $ref: '#/components/parameters/SerialNumber' get: tags: - Tables summary: Show a table entry operationId: getTableEntry description: | Same as `GET /forms/{form_token}/entries/{serial_number}`. OAuth scope: read_entries parameters: - $ref: '#/components/parameters/EntriesFields' - $ref: '#/components/parameters/EntriesIncludeLabels' responses: '200': description: One entry content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' put: tags: - Tables summary: Replace a table entry operationId: replaceTableEntry description: | Same as `PUT /forms/{form_token}/entries/{serial_number}` (full replacement). OAuth scope: write_entries requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryInput' responses: '200': description: Updated content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/EntryValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' patch: tags: - Tables summary: Partially update a table entry operationId: updateTableEntry description: | Same as `PATCH /forms/{form_token}/entries/{serial_number}` (incremental update). OAuth scope: write_entries requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryInput' responses: '200': description: Updated content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/EntryValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' delete: tags: - Tables summary: Delete a table entry operationId: deleteTableEntry description: | Same as `DELETE /forms/{form_token}/entries/{serial_number}`. OAuth scope: write_entries responses: '200': description: Deleted content: application/json: schema: type: object required: - serial_number properties: serial_number: type: integer '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' post: tags: - Tables summary: Partially update a table entry (POST) operationId: updateTableEntryViaPost description: | A POST alias for `PATCH` on the same path; it performs an incremental update. OAuth scope: write_entries requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EntryInput' responses: '200': description: Updated content: application/json: schema: $ref: '#/components/schemas/Entry' '400': $ref: '#/components/responses/EntryValidationFailed' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/entries/{serial_number}/comments": parameters: - $ref: '#/components/parameters/TableToken' - $ref: '#/components/parameters/SerialNumber' get: tags: - Comments summary: List a table entry's comments description: 'Returns all comments on this table entry in ascending order of creation time, under the same rules as form entry comments. Returns 404 (table cannot be found) when the token is not a table. OAuth scope: read_entries' operationId: listTableEntryComments responses: '200': description: List of comments content: application/json: schema: type: object required: - count - data properties: count: type: integer description: Number of comments data: type: array items: $ref: '#/components/schemas/EntryComment' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' post: tags: - Comments summary: Comment on a table entry description: 'Creates a comment on this table entry, with the same parameters and limits as form entry comments (content is required, at most 2000 characters, mentioned users must be cooperators, parent_id must belong to the same entry). Returns 404 (table cannot be found) when the token is not a table. OAuth scope: read_entries' operationId: createTableEntryComment requestBody: required: true content: application/json: schema: allOf: - $ref: '#/components/schemas/EntryCommentInput' - type: object required: - content responses: '201': description: Created; returns the comment content: application/json: schema: $ref: '#/components/schemas/EntryComment' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/tables/{table_token}/entries/{serial_number}/comments/{comment_id}": parameters: - $ref: '#/components/parameters/TableToken' - $ref: '#/components/parameters/SerialNumber' - name: comment_id in: path required: true description: Comment id schema: type: string patch: tags: - Comments summary: Update a comment on a table entry description: 'Changes the content of a table entry comment; PUT is also accepted. Only the comment''s author can edit it, otherwise returns 400; returns 404 when the comment does not belong to this entry. Returns 404 (table cannot be found) when the token is not a table. OAuth scope: read_entries' operationId: updateTableEntryComment requestBody: required: true content: application/json: schema: type: object required: - content properties: content: type: string maxLength: 2000 description: New comment content; may include @[] mentions additionalProperties: false responses: '200': description: Updated; returns the comment content: application/json: schema: $ref: '#/components/schemas/EntryComment' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' delete: tags: - Comments summary: Delete a comment on a table entry description: 'Deletes a table entry comment. The comment''s author, the table''s creator, or a cooperator with the admin role can delete it; other cooperators get 400; a comment already deleted returns 404. Returns 404 (table cannot be found) when the token is not a table. OAuth scope: read_entries' operationId: deleteTableEntryComment responses: '200': description: Deleted content: application/json: schema: type: object required: - id properties: id: type: string description: Id of the deleted comment '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/tables/{table_token}/views": get: tags: - Views summary: List a table's views description: 'Returns the views of this table visible to the current caller, under the same rules as listing form views. Returns 404 (table cannot be found) when the token is not a table (kind is not table). OAuth scope: forms' operationId: listTableViews parameters: - $ref: '#/components/parameters/TableToken' responses: '200': description: List of views content: application/json: schema: type: object required: - count - data properties: count: type: integer description: Number of views returned data: type: array items: $ref: '#/components/schemas/FormView' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' post: tags: - Views summary: Create a view on a table description: 'Creates a view on a table, with the same parameters and limits as creating a form view (at most 100 views per user per table, name at most 120 characters, an invalid filter returns 422). Returns 404 (table cannot be found) when the token is not a table. view_type can be form (a form view, a public fill page); see creating a form view for the rules. OAuth scope: forms' operationId: createTableView parameters: - $ref: '#/components/parameters/TableToken' requestBody: required: true content: application/json: schema: allOf: - $ref: '#/components/schemas/FormViewInput' - type: object required: - name responses: '201': description: Created; returns the view content: application/json: schema: $ref: '#/components/schemas/FormView' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: The request cannot be processed (view limit reached, invalid filters, model validation failure, deletion not allowed, etc.); the body is { error_description } content: application/json: schema: $ref: '#/components/schemas/ViewUnprocessableError' "/tables/{table_token}/views/{view_token}": parameters: - $ref: '#/components/parameters/TableToken' - name: view_token in: path required: true description: View token schema: type: string get: tags: - Views summary: Show a view of a table description: 'Returns one table view; only views visible to the caller can be read. Returns 404 (table cannot be found) when the token is not a table. OAuth scope: forms' operationId: getTableView responses: '200': description: View details content: application/json: schema: $ref: '#/components/schemas/FormView' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: tags: - Views summary: Update a view of a table description: 'Updates a table view''s settings; PUT is also accepted. The rules are the same as for updating a form view: only the creator can change visibility (otherwise 403), and a filter or model validation failure returns 422. Returns 404 (table cannot be found) when the token is not a table. OAuth scope: forms' operationId: updateTableView requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormViewInput' responses: '200': description: Updated; returns the view content: application/json: schema: $ref: '#/components/schemas/FormView' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: The request cannot be processed (view limit reached, invalid filters, model validation failure, deletion not allowed, etc.); the body is { error_description } content: application/json: schema: $ref: '#/components/schemas/ViewUnprocessableError' delete: tags: - Views summary: Delete a view of a table description: 'Deletes a table view. Predefined views, views whose view_scope is form, and the caller''s last visible view cannot be deleted; these return 422. Returns 404 (table cannot be found) when the token is not a table. Deleting a form view requires a predefined role that can add entries (otherwise 403); once deleted, its fill link stops working immediately, and this cannot be undone. OAuth scope: forms' operationId: deleteTableView responses: '200': description: Deleted content: application/json: schema: type: object required: - token properties: token: type: string description: Token of the deleted view '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': description: The request cannot be processed (view limit reached, invalid filters, model validation failure, deletion not allowed, etc.); the body is { error_description } content: application/json: schema: $ref: '#/components/schemas/ViewUnprocessableError' "/tables/{table_token}/views/{view_token}/entries": get: tags: - Views summary: List a table view's entries description: 'Returns entries using the table view''s filters and sort, at most 50 per page; pagination and the rules for which fields are returned are the same as for form view entries. Returns 404 (table cannot be found) when the token is not a table. OAuth scope: read_entries' operationId: listTableViewEntries parameters: - $ref: '#/components/parameters/TableToken' - name: view_token in: path required: true description: View token schema: type: string - name: next in: query required: false description: The next value from the previous page's response (a row offset, starting at 0); a negative value is treated as 0 schema: type: integer minimum: 0 - $ref: '#/components/parameters/EntriesIncludeLabels' responses: '200': description: Entry list content: application/json: schema: $ref: '#/components/schemas/EntryListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/plugins/checkin/campaigns": get: tags: - Plugins summary: List check-in campaigns description: | Lists the check-in campaigns the caller created, newest first. With an account-level credential, returns the ones the account owner created. OAuth scope: form_setting operationId: listCheckinCampaigns parameters: - name: form_token in: query required: false schema: type: string description: Only the campaigns bound to this form - name: limit in: query required: false description: How many to return, 50 by default and 100 at most. There is no paging; `total` is the full count and `count` the number returned schema: type: integer minimum: 1 maximum: 100 default: 50 responses: '200': description: Check-in campaigns content: application/json: schema: type: object properties: total: type: integer count: type: integer data: type: array items: $ref: '#/components/schemas/CheckinCampaign' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' post: tags: - Plugins summary: Create a check-in campaign description: | Turns check-in on for a form. The caller must be able to reach the form. - Same limits as picking a form in the web app: returns 400 when the form has WeChat red envelope, lucky wheel, certificate or confirmation code on, is bound to a plugin that takes over the after-submit redirect (a check-in campaign with a check-in code included), or its after-submit action is not the default message. Turn that off first. - Only one check-in campaign is in effect on a form at a time; creating one turns off the one that was in effect. - Without `checkin_field_api_code`, the form's first mobile field is used, then its first name field; with neither, returns 400. The check-in field cannot be changed afterwards. - The campaign belongs to the caller, or to the account owner with an account-level credential. The caller is also added as a verifier. - `enable_checkin_code` (on by default) rewrites the form's after-submit redirect and data push URL to the check-in code page, and overrides any Webhook already on the form (and the other way round). OAuth scope: form_setting operationId: createCheckinCampaign requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CheckinCampaignCreateInput' responses: '201': description: The check-in campaign created content: application/json: schema: $ref: '#/components/schemas/CheckinCampaign' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/plugins/checkin/campaigns/{id}": get: tags: - Plugins summary: Get a check-in campaign description: | Returns the campaign's settings, how many have checked in, and its check-in, verifier invite and management links. Only campaigns the caller created. OAuth scope: form_setting operationId: getCheckinCampaign parameters: - name: id in: path required: true schema: type: integer description: Check-in campaign id responses: '200': description: Check-in campaign content: application/json: schema: $ref: '#/components/schemas/CheckinCampaign' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: tags: - Plugins summary: Update a check-in campaign description: | Updates only the keys present in the body; PUT is accepted too. Only campaigns the caller created. Turning it back on with `enabled: true` turns off any other campaign in effect on the form. OAuth scope: form_setting operationId: updateCheckinCampaign parameters: - name: id in: path required: true schema: type: integer description: Check-in campaign id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CheckinCampaignUpdateInput' responses: '200': description: The check-in campaign as saved content: application/json: schema: $ref: '#/components/schemas/CheckinCampaign' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' delete: tags: - Plugins summary: Delete a check-in campaign description: | Deletes the campaign and unbinds it from the form; its check-in records are no longer visible. To pause check-in only, PATCH `enabled: false`. OAuth scope: form_setting operationId: deleteCheckinCampaign parameters: - name: id in: path required: true schema: type: integer description: Check-in campaign id responses: '204': description: Deleted; empty body '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/opensearch/queries": get: tags: - OpenSearch summary: List public queries description: 'Returns the public queries created by the current caller (an account access token counts as the account owner), newest first, with summary fields only. With form_token, returns only the queries under that form; returns 404 when form_token does not exist or the caller cannot access it, instead of ignoring the parameter. OAuth scope: forms' operationId: listOpensearchQueries parameters: - name: form_token in: query required: false description: Filter by form token schema: type: string responses: '200': description: Public query list content: application/json: schema: type: object required: - count - data properties: count: type: integer description: Number of queries returned data: type: array items: $ref: '#/components/schemas/OpensearchQuerySummary' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' post: tags: - OpenSearch summary: Create a public query description: 'Creates a public query on the form given by form_token, with the current caller as its creator. The caller must be able to manage the form: no access returns 404, read but not manage returns 403; a plan without the public query feature returns 402. Fields referenced in search_field_rules must be searchable fields of the form, and those in display_field_rules must be displayable fields; otherwise returns 400 listing the available api_code values. search_field_rules / display_field_rules, when passed, cannot be empty arrays; scope_conditions requires a plan that supports limiting the range of searchable entries. A preview image is generated asynchronously after saving. OAuth scope: forms' operationId: createOpensearchQuery requestBody: required: true content: application/json: schema: allOf: - $ref: '#/components/schemas/OpensearchQueryInput' - type: object required: - form_token - name - display_field_rules properties: form_token: type: string description: Token of the form the query belongs to (can also be passed as a query parameter) responses: '201': description: Created; returns the public query details content: application/json: schema: $ref: '#/components/schemas/OpensearchQuery' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/opensearch/queries/{query_token}": parameters: - name: query_token in: path required: true description: Public query token (an id is also accepted) schema: type: string get: tags: - OpenSearch summary: Show a public query description: 'Returns the public query details, including the search field rules and display field rules. The caller can read only queries it created; another user''s query returns 404 (opensearch query cannot be found). OAuth scope: forms' operationId: getOpensearchQuery responses: '200': description: Public query details content: application/json: schema: $ref: '#/components/schemas/OpensearchQuery' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: tags: - OpenSearch summary: Update a public query description: 'Updates a public query the caller created; PUT is also accepted. Only the keys present in the request are updated. Returns 400 when the query''s form has been deleted. Field rules are validated as on create: referencing a field that cannot be searched / displayed, an empty rule array, an empty name and the like all return 400. An update does not check form manage permission or whether the plan includes public queries. OAuth scope: forms' operationId: updateOpensearchQuery requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/OpensearchQueryInput' responses: '200': description: Updated; returns the public query details content: application/json: schema: $ref: '#/components/schemas/OpensearchQuery' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/opensearch/query_suggestions": get: tags: - OpenSearch summary: Suggest fields for a public query description: 'Returns the search fields and display fields a form offers for public queries, plus the recommended field api_code values, for building search_field_rules / display_field_rules. The caller must be able to manage the form: no access returns 404, read but not manage returns 403. Whether the plan includes public queries is not checked. OAuth scope: forms' operationId: listOpensearchQuerySuggestions parameters: - name: form_token in: query required: true description: Form token schema: type: string responses: '200': description: Field suggestions content: application/json: schema: type: object required: - form_token - search_fields - display_fields - recommend_search_fields - recommend_display_fields properties: form_token: type: string description: Form token search_fields: type: array description: Fields usable as search conditions items: $ref: '#/components/schemas/OpensearchQuerySuggestion' display_fields: type: array description: Fields usable as display fields items: $ref: '#/components/schemas/OpensearchDisplayQuerySuggestion' recommend_search_fields: type: array description: Recommended search field api_code values (name + mobile; empty when there is no mobile field) items: type: string recommend_display_fields: type: array description: Recommended display field api_code values (excluding private fields, display-only fields and WeChat fields) items: type: string '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' "/folders": get: tags: - Folders summary: List folders operationId: listFolders description: | Lists the folders the current user has manage permission on (form folders and table folders alike, told apart by `kind`), newest first. With an account-level credential, returns the account owner's folders. `limit` defaults to 50 and is clamped to 1 to 100; there is no paging: `total` is the full count, `count` the number returned this time. OAuth scope: forms parameters: - name: limit in: query required: false description: Maximum number to return; defaults to 50, at most 100 schema: type: integer minimum: 1 maximum: 100 default: 50 responses: '200': description: Folder list content: application/json: schema: type: object required: - total - count - data properties: total: type: integer description: Total number of folders the user can manage count: type: integer description: Number returned this time data: type: array items: $ref: '#/components/schemas/Folder' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' post: tags: - Folders summary: Create a folder operationId: createFolder description: | Creates a folder as the current user; the creator becomes the folder's manager. `kind` decides whether the folder holds forms (`form`, the default) or tables (`table`). Returns 400 `Name cannot be empty` when `name` is empty; returns 400 `Kind must be one of: form, table` when `kind` is not form / table; returns 400 when model validation fails, with the validation message in `error_description`. OAuth scope: forms requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FolderInput' responses: '201': description: Created content: application/json: schema: $ref: '#/components/schemas/Folder' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' "/predefined_choices_sets": get: tags: - Predefined Choices Sets summary: List predefined choice sets operationId: listPredefinedChoicesSets description: | Lists the current account's custom predefined choice sets (type custom), only those matching the locale of the current request (as the server implements it); the built-in global choice sets are not returned. OAuth scope: form_setting responses: '200': description: Array of choice sets content: application/json: schema: type: array items: $ref: '#/components/schemas/PredefinedChoicesSet' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' post: tags: - Predefined Choices Sets summary: Create a predefined choice set operationId: createPredefinedChoicesSet description: | Creates a custom predefined choice set in the current account. It looks up by `label`: when the account already has a set with the same label, that set's `choices` are overwritten (in effect an update); otherwise a new set is created. OAuth scope: form_setting The request body must be wrapped under the `predefined_choices_set` key; returns 400 when the key is missing. Empty strings in `choices` are dropped; neither `label` nor the remaining `choices` may be empty, otherwise returns 400 with the body `{ errors, status: "failed" }`. Returns 200 on success (not 201). requestBody: required: true content: application/json: schema: type: object required: - predefined_choices_set properties: predefined_choices_set: $ref: '#/components/schemas/PredefinedChoicesSetInput' additionalProperties: false responses: '200': description: Created (or overwritten by label) content: application/json: schema: $ref: '#/components/schemas/PredefinedChoicesSet' '400': description: Validation failed (label or choices is empty) content: application/json: schema: $ref: '#/components/schemas/PredefinedChoicesSetError' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' "/predefined_choices_sets/{id}": patch: tags: - Predefined Choices Sets summary: Update a predefined choice set operationId: updatePredefinedChoicesSet description: | Updates the `label` and / or `choices` of one of the current account's custom predefined choice sets. PUT is also accepted and behaves the same. OAuth scope: form_setting Only a set of type custom that belongs to the current account can be updated: a global set or another account's set returns 403 `{ errors: "forbidden", status: "failed" }`; an ID that does not exist returns 404 `{ errors: "not found", status: "failed" }`; a validation failure returns 400 `{ errors, status: "failed" }`. parameters: - name: id in: path required: true description: Choice set ID (24 hexadecimal characters) schema: type: string requestBody: required: true content: application/json: schema: type: object required: - predefined_choices_set properties: predefined_choices_set: $ref: '#/components/schemas/PredefinedChoicesSetInput' additionalProperties: false responses: '200': description: Updated content: application/json: schema: $ref: '#/components/schemas/PredefinedChoicesSet' '400': description: Validation failed (label or choices is empty) content: application/json: schema: $ref: '#/components/schemas/PredefinedChoicesSetError' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': description: No permission on this choice set (a global set or another account's set), or insufficient OAuth scope content: application/json: schema: oneOf: - $ref: '#/components/schemas/PredefinedChoicesSetError' - type: object required: - error_description properties: error_description: type: string '404': description: Choice set does not exist content: application/json: schema: $ref: '#/components/schemas/PredefinedChoicesSetError' delete: tags: - Predefined Choices Sets summary: Delete a predefined choice set operationId: deletePredefinedChoicesSet description: | Deletes one of the current account's custom predefined choice sets; returns 200 with no response body on success. OAuth scope: form_setting Only a set of type custom that belongs to the current account can be deleted: a global set or another account's set returns 403 `{ errors: "forbidden", status: "failed" }`; an ID that does not exist returns 404 `{ errors: "not found", status: "failed" }`. parameters: - name: id in: path required: true description: Choice set ID (24 hexadecimal characters) schema: type: string responses: '200': description: Deleted, no response body '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': description: No permission on this choice set (a global set or another account's set), or insufficient OAuth scope content: application/json: schema: oneOf: - $ref: '#/components/schemas/PredefinedChoicesSetError' - type: object required: - error_description properties: error_description: type: string '404': description: Choice set does not exist content: application/json: schema: $ref: '#/components/schemas/PredefinedChoicesSetError' "/template_usages": post: tags: - Templates summary: Create a form from a template operationId: createTemplateUsage description: | Uses a template from the template market as the current user, copies it into a new form, and returns the new form's token and edit page URL. OAuth scope: forms The template is given by `id` (or `template_id`), which takes a template token or a 24-character hexadecimal ID. Optional parameters: `tags` (tags, an array or a comma-separated string), `tag_id` / `folder_id` (the tag / folder the new form goes into), `scene` (target scene; falls back to form when the template has fields the scene does not allow), `frm` (source marker; affects the recorded created_from), `create_source`, `group_id`. Payment-related branches: - Paid template the current user has not bought: returns 200 with the body `{ template_url }` (the template purchase page URL), and no form is created. - Template uses paid features the current plan does not offer: returns 403 `{ error: "CAN_FEATURE_TRIAL", target_plan, target_trial_type, ... }` when the caller is an admin and a feature trial can be started; otherwise returns 403 `{ error: "PAID_FEATURE_REQUIRED", target_plan, template_url }`; an account from a channel partner gets 403 `{ error: "UNAVAILABLE_TO_TRIAL_OR_UPGRADE" }`. - With `form_app_trial_alert` passed and the template bound to form apps that must be bought / tried: returns 200 `{ error: "CANNOT_FORM_APP_TRIAL" | "FORM_APP_TRIAL_REQUIRED", ... }`; confirm with `confirm_unbind_form_app` / `confirm_form_app_trial` and retry. When form creation fails (failing the content risk check included), returns 400 `{ error }`. When the template does not exist, returns 404 with an HTML page, not JSON. `mobile_editor_forbidden` appears only on a mobile request when the new form has the card layout and the current plan cannot use the mobile editor. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TemplateUsageInput' responses: '200': description: Created; or not created because of a payment / form app restriction, in which case the body has `template_url` or `error` content: application/json: schema: anyOf: - type: object required: - success_url - form_token properties: success_url: type: string description: Site path of the new form's edit page (e.g. `/forms/{token}/edit`) form_token: type: string description: Token of the new form mobile_editor_forbidden: type: boolean description: true on a mobile request when the current plan cannot use the mobile editor to edit a card-layout form - type: object required: - template_url properties: template_url: type: string description: Template purchase page URL, when a paid template has not been bought - type: object required: - error properties: error: type: string enum: - CANNOT_FORM_APP_TRIAL - FORM_APP_TRIAL_REQUIRED cannot_trial_form_apps: type: array items: type: string description: Names of the form apps that must be bought need_trial_form_apps: type: array items: type: string description: Names of the form apps that need a trial expire_days: type: integer description: Days left in the form app trial template_url: type: string '400': description: Form creation failed content: application/json: schema: type: object required: - error properties: error: type: string description: Failure reason (e.g. `模板选用失败!...`) '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': description: The template has paid features the current plan does not offer, or the OAuth scope is insufficient content: application/json: schema: oneOf: - type: object required: - error properties: error: type: string enum: - PAID_FEATURE_REQUIRED - CAN_FEATURE_TRIAL - UNAVAILABLE_TO_TRIAL_OR_UPGRADE target_plan: type: string description: Code of the lowest plan that can use this template target_trial_type: type: string description: Type of feature trial that can be started in_trial_form_apps: type: array items: type: string current_trial_type: type: string current_trial_end_date: type: string template_url: type: string - type: object required: - error_description properties: error_description: type: string '404': description: Template does not exist (an HTML page is returned) content: text/html: schema: type: string "/contacts": get: tags: - Contacts summary: List contacts operationId: listContacts description: | Lists the current user's contacts page by page, by ID descending, a fixed 50 per page. With an account-level credential, returns the account owner's contacts. OAuth scope: read_contacts Cursor paging: `next` in the response is the ID of the first contact on the next page; pass it as the query parameter `next` to get that page. `next` is null when there is no more data. parameters: - name: next in: query required: false description: The `next` cursor from the previous page's response (a contact ID) schema: type: string responses: '200': description: Contact list content: application/json: schema: type: object required: - total - count - data - next properties: total: type: integer description: Total number of contacts count: type: integer description: Number on this page data: type: array items: $ref: '#/components/schemas/Contact' next: type: - string - 'null' description: Cursor for the next page; null when there is no more data '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' "/me": get: tags: - Account summary: Show the current user operationId: getCurrentUser description: | Returns the user behind the current credential. With an account-level credential (no specific user), returns the account owner. OAuth scope: users responses: '200': description: Current user content: application/json: schema: $ref: '#/components/schemas/CurrentUser' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' "/billing_account": get: tags: - Account summary: Show the current account operationId: getBillingAccount description: | Returns the account the current credential belongs to: plan, this month's usage and quota, feature trial status, and the bound payment merchant / WeChat Pay / Alipay accounts. OAuth scope: users `usage` is null when the account has no usage record for this month yet; for an add-on service with unlimited quota, only `unit`, `unlimited: true` and `consumed_quota` are returned. responses: '200': description: Account details content: application/json: schema: $ref: '#/components/schemas/BillingAccount' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' "/billing_account/users": get: tags: - Account summary: List account members operationId: listBillingAccountUsers description: | Lists the members of the current account (deactivated members included), by status ascending (active first), then by creation time, newest first. OAuth scope: users `limit` defaults to 50 and is clamped to 1 to 100; there is no paging: `total` is the total number of members, `count` the number returned this time. parameters: - name: limit in: query required: false description: Maximum number to return; defaults to 50, at most 100 schema: type: integer minimum: 1 maximum: 100 default: 50 responses: '200': description: Member list content: application/json: schema: type: object required: - total - count - data properties: total: type: integer description: Total number of members count: type: integer description: Number returned this time data: type: array items: $ref: '#/components/schemas/BillingAccountUser' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' "/billing_account/invoices": get: tags: - Account summary: List account e-invoices operationId: listBillingAccountInvoices description: | Lists the e-invoices the current account has requested (newest request first, all at once, no paging), and the spending that can be invoiced but has not been yet. Only an account admin can read it: a non-admin member gets 403 (`Only an account admin can read this.`); an account-level credential (no specific user) is treated as the account owner. OAuth scope: users responses: '200': description: E-invoices and the amount not yet invoiced content: application/json: schema: $ref: '#/components/schemas/BillingAccountInvoicesResponse' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/billing_account/payment_histories": get: tags: - Account summary: List account payment history operationId: listBillingAccountPaymentHistories description: | Lists the current account's top-ups and spending on Jinshuju (account balance transactions such as buying plans, SMS, AI points and attachment storage), newest first. This is what the account itself spent; money received through payment forms is not included. Only an account admin can read it: a non-admin member gets 403 (`Only an account admin can read this.`); an account-level credential (no specific user) is treated as the account owner. There is no paging: `limit` defaults to 50 and is clamped to 1 to 1000; `total_records` is the number of matching records, `returned_records` the number returned this time. With `include_balance=true`, `current_balance` is included (account balance and the remaining quota of each item); when records are returned, `statistics` is included (counting only the returned records). OAuth scope: users parameters: - name: start_date in: query required: false description: Start date, inclusive, parsed in Beijing time (UTC+8) as 00:00 of that day, e.g. `2024-01-01` schema: type: string examples: firstDay: value: '2024-01-01' - name: end_date in: query required: false description: End date, inclusive, parsed in Beijing time (UTC+8) as 23:59:59 of that day, e.g. `2024-12-31` schema: type: string examples: lastDay: value: '2024-12-31' - name: verb in: query required: false description: | Only records of this type; the value is the record's `verb`. Possible types: `charge` (top-up), `coupons` (voucher), `plan_charge` (buy a plan), `plan_convert` (convert a plan), `plan_for_free`, `convert_to_pro2`, `expand_entries_charge`, `sms_charge` (buy SMS), `active_mail_charge` (buy emails), `ai_points_charge` (buy AI points), `storage_quota_charge` (buy attachment storage), `audio_quota_charge` (buy audio duration), `sub_account_charge` / `sub_account_for_free` (account members), `submitter_charge` / `submitter_for_free`, `weixin_account_charge` (buy WeChat Official Accounts), `app_charge` / `app_upgrade_charge` / `app_package_charge` (apps), `template_charge` (templates), `form_application_charge` / `form_application_upgrade_charge`, `cname_protocol_charge`, `hide_report_form_charge`, `show_alipay_charge`, `gd_portal_charge` / `gd_portal_customer_charge`, `other_charge`. Any other value gives an empty result. schema: type: string examples: smsCharge: value: sms_charge - name: limit in: query required: false description: Maximum number to return; defaults to 50, at most 1000 (a larger value counts as 1000, a value below 1 as 1) schema: type: integer default: 50 - name: include_balance in: query required: false description: When `true`, `current_balance` is included. Defaults to false schema: type: boolean default: false responses: '200': description: Payment history content: application/json: schema: $ref: '#/components/schemas/BillingAccountPaymentHistoriesResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/trade/merchant": get: tags: - Trade summary: Show the 小金商户 operationId: getTradeMerchant description: | Returns the current account's 小金商户 (the merchant Jinshuju collects payments for) and its onboarding progress: merchant profile, legal entity and contact details, balance, settlement details, payment channel authorization, freeze status, bound payment forms, and the URL for the next step. - When the account has no 小金商户 yet, it still returns 200: `merchant_stage` says how far the onboarding application has got, `merchant` / `subject` / `contact` / `balance` / `settlement` / `freeze` are null, and `channels` is an empty array. - An account that collects payments through its own WeChat Pay / Alipay merchant (direct connection) has no rate, settlement account, balance or onboarding status on Jinshuju, and none of these is given here. - Sensitive fields such as bank card numbers, mobile numbers, emails and ID numbers are masked by the rules of the product's "Fund account information" page: 4 characters are kept at each end (mobile numbers keep the first 3 and last 4), and the middle is replaced with `*`. - `payment_form_tokens` holds only the payment forms the current identity can access (quick payment forms included); with an account-level credential, it is computed for the account owner. - `balance` is null when the balance lookup fails; that does not mean the balance is 0. OAuth scope: users responses: '200': description: 小金商户 details and onboarding progress content: application/json: schema: $ref: '#/components/schemas/TradeMerchant' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/trade/transactions": get: tags: - Trade summary: List payment orders operationId: listTradeTransactions description: | Lists the payment orders of the 小金商户 (orders customers place by paying on payment forms), newest order first. Only 小金商户 orders are included: orders collected through a direct connection, simulated-payment orders, and unpaid quick payment records are all left out. - The date range filters on order time, in Beijing time (UTC+8); `start_date` / `end_date` are both inclusive and must be passed together. Without them, it defaults to the last 90 days; with `order_no` and no dates, there is no time limit. `queried_range` in the response gives the range actually used (both ends null when there is no time limit). - Detail limits: the date range spans at most 90 days, and at most 200 orders match. Past either limit, no details are returned: `transactions` is null, `detail_limit` says why, and `stats` gives the transaction amount, paid count and order count for the range; narrow the range and query again. - Paging: `limit` is the page size (default and maximum 50), and `next` is a page number. When there is another page, the response carries `next` (the next page number); pass it back as is. `page_info.total` is the total number of matching orders. - Returns 404 when the account has no 小金商户. OAuth scope: users parameters: - $ref: '#/components/parameters/TradeStartDate' - $ref: '#/components/parameters/TradeEndDate' - $ref: '#/components/parameters/TradePaidStatus' - $ref: '#/components/parameters/TradePaymentChannel' - $ref: '#/components/parameters/TradeFormToken' - name: order_no in: query required: false description: Exact lookup by order number, matching one of the transaction number (`trade_no`), the merchant order number (`merchant_out_trade_no`) or the Jinshuju order number (`out_trade_no`). Without dates, there is no time limit. schema: type: string - $ref: '#/components/parameters/TradePageLimit' - $ref: '#/components/parameters/TradePageNext' responses: '200': description: Payment orders content: application/json: schema: $ref: '#/components/schemas/TradeTransactionListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/MerchantNotFound' '429': $ref: '#/components/responses/TooManyRequests' "/trade/transactions/aggregate": get: tags: - Trade summary: Aggregate payment orders operationId: aggregateTradeTransactions description: | Totals the transaction amount, paid count and order count of the 小金商户 payment orders over a date range, optionally grouped by one dimension. Orders are counted as in "List payment orders" (only 小金商户 orders; no simulated payments and no unpaid quick payment records); the totals cover the whole range and are not bound by the detail limits. - The date range filters on order time, in Beijing time (UTC+8); both ends are inclusive and must be passed together. Without them, it defaults to the last 30 days. The range spans at most 366 days; a longer one returns 400. - `transactions_amount` (transaction amount): the amount of paid-type orders minus each order's successful refunds, counted on the day the order was placed; refunded and unpaid orders contribute 0. `transactions_count` (paid count): the number of paid, partially refunded and refunding orders. `orders_count` (order count): the number of all matching orders, unpaid included. - `group_by=time` groups by time: by day for a range under 90 days, by week from 90 days, by month from 365 days; `granularity` gives the granularity, and periods without orders are filled with zero. `paid_status` / `payment_channel` make one group per value; the group whose `payment_channel` is null holds orders that have not started payment. Under the same filters, the groups add up to the total. - Returns 404 when the account has no 小金商户. OAuth scope: users parameters: - $ref: '#/components/parameters/TradeStartDate' - $ref: '#/components/parameters/TradeEndDate' - name: group_by in: query required: false description: Dimension to group by; only one dimension at a time. By default there is no grouping and only the total is returned. Any other value returns 400. schema: type: string enum: - time - paid_status - payment_channel - $ref: '#/components/parameters/TradePaidStatus' - $ref: '#/components/parameters/TradePaymentChannel' - $ref: '#/components/parameters/TradeFormToken' responses: '200': description: Payment order statistics content: application/json: schema: $ref: '#/components/schemas/TradeTransactionAggregateResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/MerchantNotFound' '429': $ref: '#/components/responses/TooManyRequests' "/trade/refunds": get: tags: - Trade summary: List refunds operationId: listTradeRefunds description: | Lists the refunds the 小金商户 issued to customers, with statistics. Refunds are filtered and sorted newest first by the time they were issued, not by the order time or the time the refund arrived. Only a 小金商户 has refund records; an account collecting payments through a direct connection has no data here. - The date range is in Beijing time (UTC+8); both ends are inclusive and must be passed together. Without them, it defaults to the last 90 days; with `refund_no` and no dates, there is no time limit. `queried_range` gives the range actually used. - `include` decides what is returned: `both` (default) returns `stats` and `refunds` together, `stats` returns the statistics alone, `records` returns the records alone. - The detail limits are those of "List payment orders" (at most 90 days, 200 records): past them, `refunds` is null, `detail_limit` says why, and `stats` is returned as usual. - `stats`: the count and amount of all matching refunds, the count and amount per status, the number of distinct orders with a successful refund, and the trend by refund issue date (only when there is a date range; by day under 90 days, by week from 90 days, by month from 365 days, periods without refunds filled with zero). In the trend, order counts are deduplicated within each period, so the sum over periods can exceed the total order count. - Paging works as in "List payment orders"; with `include=stats`, `next` is not returned. - Returns 404 when the account has no 小金商户. OAuth scope: users parameters: - $ref: '#/components/parameters/TradeStartDate' - $ref: '#/components/parameters/TradeEndDate' - name: status in: query required: false description: 'Keep only refunds in this state; records, statistics and trend are all filtered by it: `processing` (in progress), `success` (refunded), `error` (refund failed). Any other value returns 400.' schema: type: string enum: - processing - success - error - name: refund_no in: query required: false description: Exact lookup by refund number (`refund_no`). Without dates, there is no time limit. schema: type: string - $ref: '#/components/parameters/TradeInclude' - $ref: '#/components/parameters/TradePageLimit' - $ref: '#/components/parameters/TradePageNext' responses: '200': description: Refunds and statistics content: application/json: schema: $ref: '#/components/schemas/TradeRefundListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/MerchantNotFound' '429': $ref: '#/components/responses/TooManyRequests' "/trade/payouts": get: tags: - Trade summary: List payouts operationId: listTradePayouts description: | Lists the payouts the 小金商户 made from its Jinshuju balance to its own bank account, with statistics. Payouts are filtered and sorted newest first by request time; each record carries the settlement date range the payout covers, but it cannot be filtered on. Only a 小金商户 has payout records; an account collecting payments through a direct connection has no data here. - The date range is in Beijing time (UTC+8); both ends are inclusive and must be passed together. Without them, it defaults to the last 90 days. `queried_range` gives the range actually used. - `include` decides what is returned: `both` (default) returns `stats` and `payouts` together, `stats` returns the statistics alone, `records` returns the records alone. - The detail limits are those of "List payment orders" (at most 90 days, 200 records): past them, `payouts` is null, `detail_limit` says why, and `stats` is returned as usual. - `stats`: the count and amount of all matching payouts, and the count and amount per status. - Paging works as in "List payment orders"; with `include=stats`, `next` is not returned. - For the balance awaiting payout and the settlement cycle, see "Show the 小金商户". Returns 404 when the account has no 小金商户. OAuth scope: users parameters: - $ref: '#/components/parameters/TradeStartDate' - $ref: '#/components/parameters/TradeEndDate' - name: status in: query required: false description: 'Keep only payouts in this state; records and statistics are both filtered by it: `processing` (in progress), `success` (paid out), `error` (payout failed). Any other value returns 400.' schema: type: string enum: - processing - success - error - $ref: '#/components/parameters/TradeInclude' - $ref: '#/components/parameters/TradePageLimit' - $ref: '#/components/parameters/TradePageNext' responses: '200': description: Payouts and statistics content: application/json: schema: $ref: '#/components/schemas/TradePayoutListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/MerchantNotFound' '429': $ref: '#/components/responses/TooManyRequests' "/sms/audit_statuses": get: tags: - Account summary: Show SMS signature review status operationId: listSmsAuditStatuses description: | Lists the SMS signatures the current user applied for and the SMS templates under each signature, with review status and the reason a review failed, newest signature first. Returns only the current user's own signatures, not those of other members of the account; with an account-level credential, returns the account owner's signatures. Any member can call it; admin is not required. OAuth scope: users responses: '200': description: Review status of SMS signatures and templates content: application/json: schema: $ref: '#/components/schemas/SMSAuditStatusResponse' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/jamr_v": get: tags: - Utilities summary: Verify redirect parameters operationId: verifyRedirectParams security: [] description: | Lets the receiver of a "redirect to an external URL after submission" verify that the redirect parameters have not been tampered with. This endpoint needs no API credentials. When a form has redirect after submission turned on and "Fields to carry on redirect" configured, Jinshuju appends the values of the selected fields to the redirect URL, plus the signature parameter `jamr_h` (signed over the form token, the entry token and a 10-minute validity period). The receiver forwards the received `jamr_h` and all field parameters to this endpoint unchanged: the server verifies the signature, finds the form and entry, and compares the current value of each configured field with the passed parameter value (array values must be equal as a whole; other values are compared as strings). Returns 200 `{ status: "SUCCESS", message: "验证成功" }` when all match; 400 `{ status: "FAIL", message: "无效Token或者过期" }` when the `jamr_h` signature is invalid or expired; 400 `{ status: "FAIL", message: "验证失败" }` when the form / entry does not exist, a field value does not match, or a field parameter is missing. The message text follows the request language. parameters: - name: jamr_h in: query required: true description: Signature parameter carried in the redirect URL schema: type: string - name: serial_number in: query required: false description: Entry serial number carried in the redirect URL; present only when the form is set to carry that field schema: type: string responses: '200': description: Verification passed content: application/json: schema: type: object required: - status - message properties: status: type: string enum: - SUCCESS message: type: string description: e.g. `验证成功` '400': description: Signature invalid / expired, or a field value does not match content: application/json: schema: type: object required: - status - message properties: status: type: string enum: - FAIL message: type: string description: "`无效Token或者过期` or `验证失败`" "/field_types": get: tags: - Forms summary: List field types description: | Returns every field type available when creating / editing a form (or table), with the validation switches and type-specific settings each type accepts, for building `type` and the type-specific parameters in `fields`. Kept in line with the types and parameters the create endpoints actually accept. OAuth scope: forms operationId: listFieldTypes parameters: - $ref: '#/components/parameters/FieldTypeKind' responses: '200': description: Field types content: application/json: schema: $ref: '#/components/schemas/FieldTypeListResponse' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/field_types/{type}": parameters: - name: type in: path required: true description: Field type name (case-sensitive); one of the `type` values returned by `GET /field_types`, e.g. `TextField`, `RadioButton`. schema: type: string pattern: "^[A-Za-z]+$" example: NumberField get: tags: - Forms summary: Show a field type description: | Returns the validation switches and type-specific settings one field type accepts, shaped like one item of the `GET /field_types` list. Returns 404, listing the available types in `error_description`, when the type name does not exist or is not among the types available for `kind` (e.g. querying a type tables do not support with `kind=table`). OAuth scope: forms operationId: getFieldType parameters: - $ref: '#/components/parameters/FieldTypeKind' responses: '200': description: Field type details content: application/json: schema: $ref: '#/components/schemas/FieldTypeDescription' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': description: The type name does not exist or is not among the types available for `kind` content: application/json: schema: $ref: '#/components/schemas/Error' example: error_description: 'Invalid field type: Nope. Allowed types: TextField, TextArea, NumberField, ...' '429': $ref: '#/components/responses/TooManyRequests' "/entries/count": get: tags: - Entries summary: Count entries across several forms operationId: countEntriesAcrossForms description: | Counts, in one call, the entries matching the filters in each of up to 10 forms / tables, plus their total. - A token that cannot be accessed (does not exist, or does not belong to the caller) does not fail the whole request; its row returns `unavailable` with the reason instead. The total adds up only the rows that could be counted. - Field api_codes mean different things in each form, so `filters` can use only the three form-independent conditions `created_at` / `updated_at` / `creator_id`; any other field returns 400. - `keyword` is not supported (passing it returns 400); to search several forms by keyword, use `GET /entries/search`. OAuth scope: read_entries parameters: - name: form_tokens in: query required: false description: 'Required. Tokens (ids also accepted) of the forms or tables to count, comma-separated (or repeat `form_tokens[]=`), 1 to 10 after deduplication; returns 400 when empty, and 400 when more than 10. ' schema: type: string example: abc123,def456 - name: filters in: query required: false description: 'Filters, a JSON array written like `filters` of `GET /forms/{form_token}/entries`, but `field` can only be `created_at` / `updated_at` / `creator_id`. Applied to each form separately. ' schema: type: string example: '[{"field":"created_at","operator":"within_last","value":{"unit":"day","n":7}}]' responses: '200': description: Entry counts per form, with the total content: application/json: schema: $ref: '#/components/schemas/EntryCountBatchResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/entries/search": get: tags: - Entries summary: Search entries across forms operationId: searchEntriesAcrossForms description: | Runs one keyword as a full-text search across several forms / tables and returns, per form, the match count and some of the matching serial numbers (at most 50 per form), without entry content. - Search scope: the forms in `form_tokens` when given; otherwise every form and table the caller can access (for an account access token, every form and table in the account). Either way, `filters` then narrows the scope; unless `filters` specifies `entries_count`, only forms with entries are searched by default (`entries_count > 0`). - The scope holds at most 10 forms; beyond that it returns 400: narrow it with `filters`, or pass `form_tokens` directly. - Forms with no match are left out of the result; forms that cannot be accessed, where the caller's role does not allow reading entries, whose search timed out or whose search service did not respond are listed with `unavailable` giving the reason (this does not mean there was no match). OAuth scope: read_entries parameters: - name: keyword in: query required: true description: Search keyword (at most 200 characters); returns 400 when empty. schema: type: string maxLength: 200 - name: form_tokens in: query required: false description: Tokens (ids also accepted) of the forms or tables to search, comma-separated (or repeat `form_tokens[]=`), at most 10 after deduplication. When omitted, every accessible form is searched. schema: type: string example: abc123,def456 - name: filters in: query required: false description: | Filters on form attributes that narrow the search scope, a JSON array with the same syntax and fields as `filters` of `GET /forms` (`form_name` / `created_at` / `last_entry_created_at` / `entries_count`); conditions are combined with AND. Without an `entries_count` condition, `entries_count > 0` is appended automatically. schema: type: string example: '[{"field":"last_entry_created_at","operator":"within_last","value":{"unit":"day","n":30}}]' responses: '200': description: Matches per form content: application/json: schema: $ref: '#/components/schemas/EntrySearchResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/entries/stats": get: tags: - Entries summary: Count submissions per form over a date range operationId: getEntryStats description: | Counts the submissions received within a date range by every form / table the caller can access (for an account access token, every form and table in the account): returns the total, and a list of the forms that received submissions, most submissions first. - Dates are in Beijing time (UTC+8); `from` / `to` are both inclusive. - It counts submissions as they happened: imported entries count on the day of the import, and deleted entries are not subtracted, so the result may differ from a count by entry `created_at`. - The list has at most `limit` rows; when there are more, `truncated` is true, and `total` and `forms_with_data` still cover every form. - With `by` (`day` / `week` / `month`), the response also carries `buckets`: one count of the same shape for each period in the range (periods with no submissions included); weeks start on Monday, and the first and last periods are clipped to the range. The range covers at most 92 days / 53 weeks / 24 months; beyond that it returns 400, suggesting a coarser granularity or dropping `by`. OAuth scope: read_entries parameters: - name: from in: query required: true description: Start date, inclusive, `YYYY-MM-DD`. Returns 400 when missing or unparseable. schema: type: string example: '2026-09-01' - name: to in: query required: false description: End date, inclusive, `YYYY-MM-DD`; defaults to today. Returns 400 when earlier than `from` or unparseable. schema: type: string example: '2026-09-07' - name: kind in: query required: false description: Count only forms (`form`) or only tables (`table`); by default both are counted. Any other value returns 400. schema: type: string enum: - form - table - name: by in: query required: false description: Split the counts by `day` / `week` / `month`; the response carries `buckets`. Any other value returns 400. schema: type: string enum: - day - week - month - name: limit in: query required: false description: Maximum number of forms in the list, at most 100; defaults to 100, or 10 per period when `by` is given. Values above 100 are treated as 100; values below 1 fall back to the default. schema: type: integer responses: '200': description: Submission counts content: application/json: schema: $ref: '#/components/schemas/EntryStatsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/my/forms": get: tags: - Forms summary: List the forms I have submitted to operationId: listMyFilledForms description: | Returns the forms the current user has submitted entries to as a submitter (quick payment forms excluded), most recent submission first. These forms need not be created by or shared with the current user; each row gives the current user's own submission count and latest submission time, not the form's total entry count. Deleted forms do not appear in `data` (`total` still counts them). - Pagination: `next` is a row offset, passed back as is for the next page; `skip` and `next` cannot be combined. 50 rows per page by default, adjustable with `limit` (at most 1000). - An account access token has no "current user"; calling with one returns 400. OAuth scope: forms parameters: - $ref: '#/components/parameters/PageLimit' - $ref: '#/components/parameters/OffsetNext' - $ref: '#/components/parameters/EntriesSkip' responses: '200': description: Forms submitted to content: application/json: schema: $ref: '#/components/schemas/MyFilledFormListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/my/forms/{form_token}/entries": get: tags: - Entries summary: List my entries in a form operationId: listMySubmittedEntries description: | Returns the entries the current user submitted to the given form, newest first. The form need not be created by or shared with the current user: only the user's own entries are returned, with only the fields the form makes public to submitters (hidden fields are neither returned nor usable for filtering or searching). Returns an empty list when the user has not submitted. - `fields` keeps only the given public fields; unknown or non-public api_codes are skipped (no error). - `filters` works as in the entry list, but cannot filter by `creator_id` (results are already limited to the user's own) or on non-public fields; doing so returns 400. - `keyword` searches only the user's own entries and is not subject to the form's entry-count limit. - Pagination: `next` is a row offset; `skip` and `next` cannot be combined. 50 rows per page by default, adjustable with `limit` (at most 1000). - An account access token has no "current user"; calling with one returns 400. Returns 404 when the form does not exist. OAuth scope: read_entries parameters: - name: form_token in: path required: true description: Form token (`token` from `GET /my/forms`); a 24-character hexadecimal form id is also accepted. schema: type: string - name: fields in: query required: false description: Return only these fields. A comma-separated string or an array parameter (`fields[]=`) of field api_codes; unknown or non-public fields are skipped. The serial number is always returned. schema: type: string example: field_1,field_2 - $ref: '#/components/parameters/EntriesFilters' - $ref: '#/components/parameters/EntriesKeyword' - $ref: '#/components/parameters/EntriesIncludeLabels' - $ref: '#/components/parameters/PageLimit' - $ref: '#/components/parameters/OffsetNext' - $ref: '#/components/parameters/EntriesSkip' responses: '200': description: The current user's own entries content: application/json: schema: $ref: '#/components/schemas/MySubmittedEntryListResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': description: The form does not exist content: application/json: schema: $ref: '#/components/schemas/Error' example: error_description: Form not found — check the token. '429': $ref: '#/components/responses/TooManyRequests' "/my/search": get: tags: - Entries summary: Search my entries operationId: searchMySubmittedEntries description: | Searches the current user's own entries across forms with one keyword (only fields the form makes public to submitters are searched), and returns the match count and serial numbers for each matching form. - `keyword` is required; returns 400 when empty. - By default, searches every form the current user has submitted to (quick payment forms excluded); `form_tokens` limits it to some of them, and tokens not in the user's submission history are ignored. Returns 400 when more than 20 forms are in the search; narrow them with `form_tokens`. - Forms with no match are left out of the result; when a form cannot be searched (e.g. the keyword is too long), that form returns `unavailable` with an explanation and the other forms return as usual. - At most 50 serial numbers are returned per form; `matched` is the form's actual total match count. - An account access token has no "current user"; calling with one returns 400. OAuth scope: read_entries parameters: - name: keyword in: query required: true description: Search keyword (at most 200 characters), fuzzy-matched in the form's public searchable fields. schema: type: string minLength: 1 - name: form_tokens in: query required: false description: Search only these forms. Comma-separated form tokens, or an array parameter (`form_tokens[]=`). schema: type: string example: aBc123,dEf456 responses: '200': description: Matches per form content: application/json: schema: $ref: '#/components/schemas/MySearchResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' "/fill/f/{form_token}": get: tags: - Fill summary: Show a form's fill page operationId: getFillFormPage description: | Reads the fill page behind a fill link (`/f/`): its title, description, the fields to fill in, and whether the current user can submit right now. The caller reads it as a submitter holding the link and needs no permission on the form or table; only what the fill page shows is returned. - `fields` lists the public fields in fill-page order, shaped like `fields` when reading a form; for a form view, column names, descriptions and required flags already follow the view's settings. - Submission is possible only when `status.key` is `open`; other values (such as `not_opened`, `closed`, `password_required`, `unauthorized`, `submission_prevented`, `fill_frequency_limited`: the current user has used up the submissions the fill page allows) are explained in `status.message`; when the page is not yet open or has closed on schedule, `status.open_info` gives the open period. - `blockers` lists requirements only the submitter can complete on the page (captcha, SMS verification, WeChat identity, payment, etc.); when it is not empty, submission is refused and the form must be filled in a browser. - `manageable` is returned only when the current user can already read the underlying form or table, and gives its token and name. - An account access token has no "current user"; calling with one returns 400. OAuth scope: submit_entries parameters: - name: form_token in: path required: true description: The token in the fill link `/f/`. schema: type: string responses: '200': description: Fill page content: application/json: schema: $ref: '#/components/schemas/FillPage' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': description: The fill page does not exist content: application/json: schema: $ref: '#/components/schemas/Error' example: error_description: Fill page not found — check the link. '429': $ref: '#/components/responses/TooManyRequests' "/fill/f/{form_token}/entries": post: tags: - Fill summary: Submit an entry through a form's fill page operationId: createFillFormEntry description: | Submits one entry through the fill page as the current user, the same as clicking "Submit" on the page: only fields visible on the fill page are accepted, required fields are checked as the fill page sets them, the submitter is recorded as the current user (the entry shows up in "My submissions"), and an entry submitted through a form view records which view it came from. - Returns 403 when the fill page is not open, with the reason in `status`; returns 422 listing the reasons when `blockers` is not empty. - Returns 422 when a field value is invalid, with `errors` explaining each by field api_code. - Each user can submit at most 30 times per hour; beyond that returns 429. - An account access token has no "current user"; calling with one returns 400. OAuth scope: submit_entries parameters: - name: form_token in: path required: true description: The token in the fill link `/f/`. schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FillEntryRequest' responses: '201': description: Submitted content: application/json: schema: $ref: '#/components/schemas/FillEntryCreated' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': description: The fill page is not open content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: The fill page does not exist content: application/json: schema: $ref: '#/components/schemas/Error' '422': description: The fill page has requirements the API cannot fulfil, or a field value is invalid content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/TooManyRequests' "/fill/v/{view_token}": get: tags: - Fill summary: Show a form view's fill page operationId: getFillViewPage description: | Reads the fill page behind a fill link (`/v/`): its title, description, the fields to fill in, and whether the current user can submit right now. The caller reads it as a submitter holding the link and needs no permission on the form or table; only what the fill page shows is returned. - `fields` lists the public fields in fill-page order, shaped like `fields` when reading a form; for a form view, column names, descriptions and required flags already follow the view's settings. - Submission is possible only when `status.key` is `open`; other values (such as `not_opened`, `closed`, `password_required`, `unauthorized`, `submission_prevented`, `fill_frequency_limited`: the current user has used up the submissions the fill page allows) are explained in `status.message`; when the page is not yet open or has closed on schedule, `status.open_info` gives the open period. - `blockers` lists requirements only the submitter can complete on the page (captcha, SMS verification, WeChat identity, payment, etc.); when it is not empty, submission is refused and the form must be filled in a browser. - `manageable` is returned only when the current user can already read the underlying form or table, and gives its token and name. - An account access token has no "current user"; calling with one returns 400. OAuth scope: submit_entries parameters: - name: view_token in: path required: true description: The token in the fill link `/v/`. schema: type: string responses: '200': description: Fill page content: application/json: schema: $ref: '#/components/schemas/FillPage' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': description: The fill page does not exist content: application/json: schema: $ref: '#/components/schemas/Error' example: error_description: Fill page not found — check the link. '429': $ref: '#/components/responses/TooManyRequests' "/fill/v/{view_token}/entries": post: tags: - Fill summary: Submit an entry through a form view's fill page operationId: createFillViewEntry description: | Submits one entry through the fill page as the current user, the same as clicking "Submit" on the page: only fields visible on the fill page are accepted, required fields are checked as the fill page sets them, the submitter is recorded as the current user (the entry shows up in "My submissions"), and an entry submitted through a form view records which view it came from. - Returns 403 when the fill page is not open, with the reason in `status`; returns 422 listing the reasons when `blockers` is not empty. - Returns 422 when a field value is invalid, with `errors` explaining each by field api_code. - Each user can submit at most 30 times per hour; beyond that returns 429. - An account access token has no "current user"; calling with one returns 400. OAuth scope: submit_entries parameters: - name: view_token in: path required: true description: The token in the fill link `/v/`. schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FillEntryRequest' responses: '201': description: Submitted content: application/json: schema: $ref: '#/components/schemas/FillEntryCreated' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': description: The fill page is not open content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: The fill page does not exist content: application/json: schema: $ref: '#/components/schemas/Error' '422': description: The fill page has requirements the API cannot fulfil, or a field value is invalid content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/TooManyRequests' "/tables/{table_token}/folder": patch: tags: - Tables summary: Move a table into a folder description: | Moves a table into a folder, or out of its folder (`folder_token` set to null); PUT is also accepted. The move affects only the calling user's folder placement. OAuth scope: forms - The request body must include the `folder_token` key (its value may be null); otherwise 400. - `folder_token` accepts only a folder token (not an id); returns 404 when the folder does not exist or the current user lacks manage permission on it. - The target folder's kind must be table; otherwise 400. - Returns 404 `table cannot be found` when the token is not a table's. operationId: moveTableToFolder parameters: - $ref: '#/components/parameters/TableToken' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FormFolderMoveInput' responses: '200': description: Move result content: application/json: schema: $ref: '#/components/schemas/TableFolderMoveResult' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' components: securitySchemes: bearerAuth: type: http scheme: bearer description: | `Authorization: Bearer ACCESS_TOKEN`. Accepts personal access tokens, account access tokens (Enterprise plan) and OAuth 2.0 tokens. OAuth tokens can call only the endpoints their scopes allow: `forms` (forms / tables / views / folders / public queries / templates), `form_setting` (form settings, predefined choice sets), `read_entries` / `write_entries` (entries, comments, attachment uploads, WeChat authorization sessions), `submit_entries` (fill pages and submitting through them), `read_contacts` (contacts), `users` (current user / account and its members, e-invoices, payment history / 小金商户 and transactions / SMS signature review status), `public` (everything else). parameters: FormToken: name: form_token in: path required: true description: Form token (`token` from `GET /forms`); a 24-character hexadecimal form id is also accepted. schema: type: string TableToken: name: table_token in: path required: true description: Table token (`token` from `GET /tables`); a 24-character hexadecimal table id is also accepted. schema: type: string ViewToken: name: view_token in: path required: true description: View token (`token` from `GET /forms/{form_token}/views`) schema: type: string SerialNumber: name: serial_number in: path required: true description: Entry serial number schema: type: integer FormsQ: name: q in: query required: false description: Fuzzy match on name (case-insensitive; matches both the public name and the in-product name). Accepts several values (`q[]=A&q[]=B`), matching forms whose name contains any of them. Equivalent to `filters=[{"field":"form_name","operator":"like","value":...}]`. schema: type: string FormsFilters: name: filters in: query required: false description: | Filters, a JSON array; conditions are combined with AND. Filterable fields and operators: | field | type | operators | |---|---|---| | `form_name` | text | `eq` `ne` `any_in` `none_in` `like` `not_like` | | `created_at` | time | `eq` `ne` `gte` `gt` `lte` `lt` `within_last` | | `last_entry_created_at` | time | same as above (forms that have never received an entry have no value) | | `entries_count` | integer | `eq` `ne` `gte` `gt` `lte` `lt` | The value of `within_last` looks like `{"unit":"day","n":30}` (unit can be minute / day / week / month), meaning the window going back from now. Example: `[{"field":"last_entry_created_at","operator":"within_last","value":{"unit":"day","n":7}}]` schema: type: string example: '[{"field":"entries_count","operator":"gte","value":1}]' FormsNext: name: next in: query required: false description: "`next` from the previous page's response, passed back as is to get the next page. Cannot be combined with `skip`." schema: type: string FormsSkip: name: skip in: query required: false description: Starting row offset (from 0, at most 10000), for reading in parallel slices; the returned `next` still pages onward. Cannot be combined with `next`. schema: type: integer minimum: 0 maximum: 10000 EntriesFields: name: fields in: query required: false description: Return only these fields. A JSON array, a comma-separated string or a repeated parameter, of field api_codes; the serial number is always returned. Returns 400 listing the available fields when an api_code is unknown. schema: type: string example: field_1,field_2 EntriesFilters: name: filters in: query required: false description: | Filters, a JSON array of `{"field": "", "operator": "", "value": ...}` items (`field` can also be written as `api_code` / `trigger`); conditions are combined with AND. - All operators: `eq` `ne` `any_in` `none_in` `between` `not_between` `null` `not_null` `gte` `gt` `lte` `lt` `like` `not_like` `within_last`, aliases `equal` / `not_equal` / `start` (=gte) / `end` (=lte). Each field type accepts only some of them; an unsupported one returns 400 listing the available operators. - For choice fields (single choice / multiple choice / drop-down / cascading drop-down), `value` can be a choice api_code or a choice label; a cascading drop-down also accepts a `level1-level2` path. - For `between` / `not_between`, `value` is a two-element array `[min, max]`; matrix / table fields need `{"": [min, max]}`. - `within_last` works only on date fields; `value` looks like `{"unit":"day","n":30}` (unit can be minute / day / week / month). - `creator_id` is a special field that filters by submitter with `eq` (the value is a user id), and can appear only once. - `serial_number` is a special field that filters by serial number with `eq` / `any_in`; several conditions are intersected. - For a relation field (RelationField), the `value` of `any_in` / `none_in` is serial numbers of entries in the related table; returns 400 when a serial number does not exist. - With a `created_at` condition, results are sorted by creation time instead. schema: type: string example: '[{"field":"field_3","operator":"any_in","value":["选项 A","选项 B"]}]' EntriesKeyword: name: keyword in: query required: false description: Full-text keyword (at most 200 characters), fuzzy-matched across all searchable fields. Forms with more than 99999 entries and no analytics engine enabled do not support full-text search (returns 400), unless `creator_id` also restricts the submitter. schema: type: string maxLength: 200 EntriesSort: name: sort in: query required: false description: | Sort rules, a JSON array of `{"api_code": "", "order": "asc"|"desc"}` items, applied in order, with ascending serial number appended automatically at the end. Only sortable fields are allowed; otherwise returns 400 listing the sortable fields. With `sort`, `next` becomes a row offset. schema: type: string example: '[{"api_code":"created_at","order":"desc"}]' EntriesCreatedAt: name: created_at in: query required: false description: Return only entries created at or after this time (parsed in Beijing time, UTC+8, e.g. `2024-01-01` or `2024-01-01 08:00:00`), sorted by creation time ascending instead. Returns 400 when the format cannot be parsed. Ignored when given together with `filters` / `keyword`. schema: type: string EntriesNext: name: next in: query required: false description: "`next` from the previous page's response. Under the default sort it is a serial-number cursor (returns entries with serial number ≥ this value); with filters / creation-time ordering / an explicit sort it is a row offset. Cannot be combined with `skip`. Also accepts a string: one starting with an integer is read as that integer, anything else as 0, i.e. starting from the first page." schema: type: - integer - string EntriesSkip: name: skip in: query required: false description: Starting row offset (from 0, max 10000), for reading in parallel slices. Cannot be combined with `next`. schema: type: integer minimum: 0 maximum: 10000 FieldDataChecks: name: checks in: query required: true description: | Targets to check, a JSON array (1 to 100 items), each item one field or one choice: | Key | Type | Description | |---|---|---| | `field_api_code` | string | Required. api_code of the field to check; to check one column of a table field / matrix field, pass that column's api_code and also pass `parent_field` | | `choice_value` | string | Optional. To check only one choice, pass that choice's api_code; omitted, checks whether the whole field has any data | | `choice_type` | string | Optional, used with `choice_value`: `choice` (default), `statement` / `dimension` for matrix fields, `level_1` to `level_4` for cascading drop-downs | | `parent_field` | string | Optional. When checking one column of a matrix / table field, the api_code of the parent field | | `check_extended_text` | boolean | Optional. When `true`, checks whether the choice's "Other" extra text has any data | | `goods_item_dimension_options` | object | Optional. When checking one spec of a goods field, the mapping of spec dimensions to options | schema: type: string example: '[{"field_api_code":"field_1"},{"field_api_code":"field_3","choice_value":"Yb2d"}]' FieldTypeChangeChecks: name: checks in: query required: true description: | Type conversions to preview, a JSON array (1 to 20 items), one field per item: | Key | Type | Description | |---|---|---| | `field_api_code` | string | Required. api_code of the field to convert | | `target_type` | string | Required. Target field type; see `GET /field_types` for values (`GET /field_types?kind=table` for tables) | | `target_precision` | string | Optional. When the target is `DateTimeField`, the date precision the edit will use (`month` / `day` / `minute` / `second`), so the preview matches the actual conversion; ignored otherwise | schema: type: string example: '[{"field_api_code":"field_1","target_type":"RadioButton"}]' FieldTypeKind: name: kind in: query required: false description: With `table`, answers with the column types tables can use; omitted or any other value, answers with the field types forms can use. schema: type: string example: table AggregateMetrics: name: metrics in: query required: false description: | Required. Metrics to compute, a JSON array of 1 to 20 items, each `{"func": "", "field": ""}`; returns 400 when missing or empty. The available functions depend on the field (the field's `analytics.agg_funcs` is authoritative): | Field | Functions | |---|---| | All fields | `count` `count_non_empty` `count_empty` | | Text | adds `count_unique` | | Number | adds `count_unique` `sum` `avg` `min` `max` `stddev` `median` `p25` `p75` `p90` | | Date | adds `count_unique` `min` `max` | schema: type: string example: '[{"func":"sum","field":"field_5"},{"func":"count","field":"field_1"}]' AggregateDimensions: name: dimensions in: query required: false description: | Fields to group by, a JSON array of at most 2 items, each `{"field": "", "bucket": ""}`. Only fields whose `analytics.groupable` is true can be grouped by; a date field must have a `bucket` (`day` / `week` / `month`, in Beijing time, UTC+8), and a non-date field must not have a `bucket`. schema: type: string example: '[{"field":"field_3"},{"field":"created_at","bucket":"month"}]' AggregateLimit: name: limit in: query required: false description: Maximum number of groups returned when grouping. Defaults to 20, max 200 (larger values are treated as 200; values below 1 use the default). Ignored without grouping. schema: type: integer default: 20 SummaryFields: name: fields in: query required: false description: 'Summarize only these fields: field api_codes, comma-separated (or repeat `fields[]=`), returned in the order given. Defaults to every analyzable field. Returns 400, listing the analyzable fields, when a field is not analyzable or the caller has no permission to read it.' schema: type: string example: field_1,field_3 SummaryIncludeOverview: name: include_overview in: query required: false description: Whether to return `overview` (matching count and entries added today). Defaults to true. schema: type: boolean default: true EntriesIncludeLabels: name: include_labels in: query required: false description: | When true, each form field value in an entry becomes `{"label": "", "value": }`, saving a second read of the form structure. System keys (such as `serial_number`, `creator_id`, `token`) and the exam / evaluation `_extra_value` stay as they are. Defaults to false. schema: type: boolean default: false PageLimit: name: limit in: query required: false description: Page size. Defaults to 50, max 1000 (larger values are treated as 1000). With 0, returns only `total`, and `data` is empty. schema: type: integer default: 50 OffsetNext: name: next in: query required: false description: "`next` from the previous page's response (a row offset, starting at 0); pass it back unchanged to get the next page. Cannot be combined with `skip`." schema: type: integer minimum: 0 FormsSort: name: sort in: query required: false description: | Sort rules, a JSON array, each item `{"field": "", "order": "asc"|"desc"}` (order defaults to asc), applied in order. Sortable fields: `created_at`, `last_entry_created_at`, `entries_count`; any other field, an invalid order or unparseable JSON returns 400. With `sort`, `next` becomes a cursor of the form `row:`, usable only in requests with the same `sort`; rows with equal values may change order between pages. schema: type: string example: '[{"field":"last_entry_created_at","order":"desc"}]' IncludeTransactions: name: include_transactions in: query required: false description: When `true`, forms bound to a payment account (merchant account / WeChat Pay / Alipay) carry `transactions` payment statistics; unbound forms have no such key. Not included by default. schema: type: boolean default: false EntryImportId: name: id in: path required: true description: Import job ID (the `job_id` returned when the import was created) schema: type: string TradeStartDate: name: start_date in: query required: false description: Start date, inclusive, `YYYY-MM-DD`, in Beijing time (UTC+8). Must be given together with `end_date` and must not be later than `end_date`; returns 400 when only one of them is given or it cannot be parsed. See each endpoint for the default range. schema: type: string example: '2026-09-01' TradeEndDate: name: end_date in: query required: false description: End date, inclusive, `YYYY-MM-DD`, in Beijing time (UTC+8). Must be given together with `start_date`. schema: type: string example: '2026-09-30' TradePaidStatus: name: paid_status in: query required: false description: 'Keep only orders in these payment statuses, comma-separated (or repeat `paid_status[]=`): `paid`, `unpaid`, `refunded`, `refunding` (refund in progress), `partial_refunded` (partially refunded). Returns 400 when any value is unknown; by default every status is kept (unpaid included).' explode: false schema: type: array items: type: string enum: - paid - unpaid - refunded - refunding - partial_refunded example: - paid - refunding TradePaymentChannel: name: payment_channel in: query required: false description: 'Keep only orders paid through this channel: `wxpay` (WeChat Pay), `alipay` (Alipay). Any other value returns 400.' schema: type: string enum: - wxpay - alipay TradeFormToken: name: form_token in: query required: false description: Keep only orders of this payment form. The form token (a 24-character hex form id is also accepted), available from `payment_form_tokens` in `GET /trade/merchant`; returns 400 when the form does not exist or is not accessible to the current identity. schema: type: string TradeInclude: name: include in: query required: false description: 'What to return: `both` (default) returns statistics and records, `stats` returns statistics only, `records` returns records only. Any other value returns 400.' schema: type: string enum: - both - stats - records default: both TradePageLimit: name: limit in: query required: false description: Page size. Defaults to 50, which is also the max (larger values are treated as 50; values below 1 use the default). schema: type: integer default: 50 TradePageNext: name: next in: query required: false description: "`next` from the previous page's response (a page number, starting at 1); pass it back unchanged to get the next page. Defaults to page 1." schema: type: integer responses: BadRequest: description: Invalid request parameters or data content: application/json: schema: $ref: '#/components/schemas/Error' FormSettingBadRequest: description: The generic error_description shape when the request does not follow this document; the errors/status shape when model validation fails content: application/json: schema: oneOf: - $ref: '#/components/schemas/Error' - $ref: '#/components/schemas/FormSettingSaveFailed' Unauthorized: description: 'Unauthenticated: the token is invalid or revoked' content: application/json: schema: $ref: '#/components/schemas/Error' example: error_description: Invalid or revoked token PaymentRequired: description: The current plan does not include API v1 content: application/json: schema: $ref: '#/components/schemas/Error' Forbidden: description: 'Forbidden: the OAuth token lacks the required scope, or a business rule refused the operation' content: application/json: schema: $ref: '#/components/schemas/Error' example: error_description: OAuth token scope is insufficient NotFound: description: The resource does not exist or is not accessible to the current identity (a personal token can access only the forms its user created or that were shared with that user) content: application/json: schema: $ref: '#/components/schemas/Error' example: error_description: form cannot be found TooManyRequests: description: Rate limit exceeded headers: Retry-After: description: Seconds to wait before retrying schema: type: integer X-RateLimit-Limit: description: Quota for the current window (1 hour) schema: type: integer X-RateLimit-Remaining: description: Requests left in the current window schema: type: integer X-RateLimit-Reset: description: Unix timestamp when the quota resets schema: type: integer content: application/json: schema: $ref: '#/components/schemas/RateLimitError' EntryValidationFailed: description: 'Entry validation failed or a parameter is invalid. When field validation fails, `error_description` is a JSON string serialized from `{ "": ["error message"] }`' content: application/json: schema: $ref: '#/components/schemas/Error' example: error_description: '{"field_2":["不能为空"]}' MerchantNotFound: description: The current account has no 小金商户, so it has no 小金商户 orders, refunds or payouts; see `GET /trade/merchant` for onboarding progress content: application/json: schema: $ref: '#/components/schemas/Error' schemas: Error: type: object required: - error_description properties: error_description: type: string description: Human-readable error description RateLimitError: type: object properties: error: type: string examples: - rate_limit_exceeded error_description: type: string retry_after: type: integer description: Seconds to wait before retrying limit: type: integer remaining: type: integer reset_at: type: string format: date-time plan: type: string description: Code of the current plan upgrade_url: type: string format: uri Creator: type: object properties: name: type: - string - 'null' description: Creator's name (nickname when there is no name) FormSummary: type: object required: - name - token - tags - created_at - entries_count - last_entry_created_at - creator properties: name: type: string description: Form name (the public name) token: type: string tags: type: array items: type: string description: Tags the current identity put on this form (for an account token, the union of all members' tags) created_at: type: string format: date-time entries_count: type: integer description: Entry count of the form last_entry_created_at: type: - string - 'null' format: date-time description: When the latest entry was received (UTC); null when the form has never received an entry creator: $ref: '#/components/schemas/Creator' transactions: $ref: '#/components/schemas/FormTransactions' FormListResponse: type: object required: - total - count - data - next properties: total: type: integer description: Total number of forms matching the conditions count: type: integer description: Number of items on this page data: type: array items: $ref: '#/components/schemas/FormSummary' next: type: - string - 'null' description: 'Cursor for the next page: the form id under the default sort, `row:` when `sort` is given; null on the last page' Form: type: object required: - name - token - url - description - fields - setting properties: name: type: string token: type: string url: type: string format: uri description: Public fill URL of the form (built from the account's custom domain / subdomain; cannot be derived from the token) description: type: - string - 'null' description: Form description (may be HTML rich text) fields: type: array description: Fields in form order; each element is an object whose single key is the field's api_code items: $ref: '#/components/schemas/FieldMap' setting: description: Form settings; an empty object when the form has no settings yet allOf: - $ref: '#/components/schemas/FormSetting' FieldMap: type: object description: 'Single-key object: the key is the field''s api_code, the value is the field definition' minProperties: 1 maxProperties: 1 additionalProperties: $ref: '#/components/schemas/FieldDefinition' examples: - field_1: label: 姓名 api_code_alias: type: single_line_text notes: '' private: false validation: required: true FieldDefinition: type: object description: | Field definition. Every field has `label` / `api_code_alias` / `type` / `notes` / `private` / `validation`; the other properties appear according to `type`. How `type` values map to fields: | type | Field | |---|---| | `single_line_text` | Single-line text | | `paragraph_text` | Multi-line text | | `name` / `id_card` / `mobile` / `email` / `phone` / `link` / `address` / `geo_location` | Name / ID card / Mobile / Email / Phone / Website / Address / Geolocation | | `single_choice` / `multiple_choice` / `drop_down` / `cascade_drop_down` | Single choice / Multiple choice / Drop-down / Cascading drop-down (the color mark is also `drop_down`) | | `image_radio_button` / `image_check_box` | Image single choice / Image multiple choice | | `number` / `formula` / `rating` / `nps` / `boolean` | Number / Formula / Rating / NPS / Yes/No | | `date_time` / `date` / `time` | Date / Date (legacy) / Time | | `attachment` / `audio` / `e_signature` | File upload / Audio / E-signature | | `likert` / `matrix` / `matrix_scale` / `table` / `multiple_blanks` / `sort` | Matrix single choice / Matrix fill-in / Matrix scale / Table / Inline blanks / Ranking | | `goods` / `reservation` | Goods / Reservation | | `form_association` / `reversed_association` | Form association / Reverse association | required: - label - type - notes - private - validation properties: label: type: string description: Field label api_code_alias: type: - string - 'null' description: Alias for the field's api_code; once set, entries are read and written with the alias as the key type: type: string description: Field type; see the table above for values notes: type: - string - 'null' description: Field notes (may be HTML rich text) private: type: boolean description: Whether the field is hidden validation: $ref: '#/components/schemas/FieldValidation' choices: type: array description: Choices (single choice / multiple choice / drop-down / cascading drop-down / image choice / matrix single choice / ranking) items: $ref: '#/components/schemas/Choice' allow_other: type: boolean description: Whether there is an "Other" choice (choice fields) statements: type: array description: Statements (matrix single choice / matrix fill-in / matrix scale) items: $ref: '#/components/schemas/Statement' dimensions: type: array description: Sub-fields (matrix fill-in / matrix scale / table / inline blanks); each item is a single-key object keyed by the sub-field's api_code, and sub-fields carry only the common properties items: $ref: '#/components/schemas/FieldMap' placeholder: type: - string - 'null' description: Prompt of an inline-blanks field, with each blank marked by the placeholder `${field_x}$` max_file_quantity: type: integer description: 'Attachment field: maximum number of files to upload' media_type: type: object description: 'Attachment field: allowed file types' properties: type: type: string description: "`unlimited` or a specific type group" value: type: array items: type: string max_duration: type: - integer - 'null' description: 'Audio field: maximum duration (seconds)' precision: description: For date fields, a precision enum (`month` / `day` / `minute` / `second`, etc.); for number / formula fields, the number of decimal places oneOf: - type: string - type: integer display_precision: type: integer description: 'Number / formula field: decimal places shown' display_as_percentage: type: boolean thousands_separator: type: boolean currency_symbol: type: string currency_symbol_position: type: string enum: - prefix - suffix formula: type: - string - 'null' description: 'Formula field: the formula the server evaluates' formula_display: type: - string - 'null' description: 'Formula field: the admin-readable formula' goods_items: type: array description: 'Goods field: goods items' items: $ref: '#/components/schemas/GoodsItem' reservation_items: type: array description: 'Reservation field: reservation items' items: $ref: '#/components/schemas/ReservationItem' associated_form_token: type: - string - 'null' description: 'Form association: token of the associated form' associated_field_api_code: type: string description: 'Form association: given only when there is a single association key' associated_field_api_codes: type: array items: type: string description: 'Form association: api_codes of all association keys' display_field_settings: type: array description: 'Form association: display field settings' items: $ref: '#/components/schemas/DisplayFieldSetting' allow_reverse_association: type: boolean description: 'Form association: whether the reverse association shows on the associated form' reverse_display_field_api_codes: type: array items: type: string description: 'Form association: api_codes of the fields the reverse association shows; given when reverse association is on' rating_type: type: string description: 'Rating field: appearance (e.g. `star`)' rating_max: type: integer description: 'Rating field: scale' range_max: type: - integer - 'null' minimum_ratings_display_text: type: - string - 'null' description: 'NPS field: text for the lowest score' maximum_ratings_display_text: type: - string - 'null' description: 'NPS field: text for the highest score' highlight_color: type: - string - 'null' description: 'NPS field: highlight color' include_second: type: boolean description: 'Time field: whether it is precise to the second (present only when true)' analytics: $ref: '#/components/schemas/FieldAnalytics' additionalProperties: true FieldValidation: type: object description: Field validation rules; only the rules in effect appear properties: required: type: boolean description: Required unique: type: boolean description: Must not repeat a value from an existing entry white_list_limit: type: boolean description: Whitelist limit is on access_control_list_limit: type: boolean description: Whitelist / blacklist limit is on access_control_type: type: string enum: - white - black description: List type white_list_values: type: array items: type: string description: Whitelist values (single-line text / mobile) acl_values: type: array items: type: string description: List values (single-line text / mobile) min_selected: type: integer description: Minimum number of selections (multiple choice / image multiple choice / ranking) max_selected: type: integer description: Maximum number of selections (multiple choice / image multiple choice / ranking) minimum_length: type: integer description: Minimum number of characters (text fields) maximum_length: type: integer description: Maximum number of characters (text fields) min: type: number description: Minimum value (number) max: type: number description: Maximum value (number) start: type: string description: Start date (date field) end: type: string description: End date (date field) additionalProperties: true Choice: type: object required: - name - value properties: name: type: string description: Choice label value: type: string description: Choice api_code (either it or the choice label works when writing entries) hidden: type: boolean quota: type: - integer - 'null' description: Choice quota (absent when unset or when the quota is hidden) operand_value: type: number description: Value assigned to the choice allow_extended_text: type: boolean description: Extra text can be added when selected extended_text_required: type: boolean is_other: type: boolean description: Whether this is the "Other" choice image_url: type: - string - 'null' description: Image URL of an image choice large_path: type: - string - 'null' description: Large image URL of an image choice sub_choices: type: array description: Child choices (cascading drop-down) items: $ref: '#/components/schemas/Choice' additionalProperties: true Statement: type: object required: - name - value properties: name: type: string description: Statement text value: type: string description: Statement api_code GoodsItem: type: object properties: name: type: string value: type: string description: Goods item api_code description: type: - string - 'null' inventory: type: - integer - 'null' hidden: type: boolean price: type: - number - 'null' description: Price when there are no specs; null when there are specs original_price: type: - number - 'null' skus: type: array items: $ref: '#/components/schemas/GoodsSku' GoodsSku: type: object properties: spec: type: object additionalProperties: type: string description: 'Spec: keys are spec dimension names, values are spec options' price: type: - number - 'null' original_price: type: - number - 'null' inventory: type: - integer - 'null' ReservationItem: type: object required: - name - value - hidden properties: name: type: string value: type: string description: Reservation item api_code hidden: type: boolean DisplayFieldSetting: type: object properties: api_code: type: string public_display: type: boolean privacy_safe: type: boolean additionalProperties: true EntryData: type: object description: | One entry. Keys are field api_codes (a field with an api_code_alias is keyed by the alias), plus these system keys: `token`, `serial_number`, `created_at`, `updated_at`, `creator_name` (submitter's name), `color_mark` (color mark), `info_filling_duration` (time spent filling in, seconds), `info_platform`, `info_os`, `info_browser`, `info_region` (`{country, province, city}`), `info_remote_ip`, and, depending on the form's features, `gen_code` (confirmation code), `total_price` / `preferential_price` (when there are goods), `x_field_weixin_*` (WeChat info), `referral_link` and others. Exam / evaluation questions also add `_extra_value: { correct_answer, score }`; reverse association fields add `_entries`, and association fields add `_related_entries`. Value shape by field type: | Field | Value | |---|---| | Single-line / multi-line text, name, mobile, email, phone, website, ID card | String | | Single choice, drop-down, image single choice | Choice label (string) | | Multiple choice, image multiple choice | Array of choice labels | | Cascading drop-down | `{"level_1": "...", "level_2": "..."}` | | Number, rating, NPS, formula | Number (a rating may be a string) | | Yes/No | Boolean | | Date | Beijing time (UTC+8) string formatted to the field's precision, e.g. `2021-09-23` | | Time | `HH:MM` or `HH:MM:SS` | | File upload | Array of download URLs (signed, valid for 10 years) | | E-signature | Download URL string | | Audio | `{"url": "...", "audio_text": "..."}` | | Address | `{"province","city","district","street"}` | | Geolocation | `{"longitude","latitude","address"}` | | Goods | `[{"name","number","price","original_price","inventory","layout","spec"?}]` | | Matrix fill-in / matrix scale | `[{"statement": "statement label", "dimensions": {"column name": value}}]` | | Matrix single choice | `[{"statement": "statement label", "choice": "choice label"}]` (the multiple-choice style has a `choices` array) | | Table | `[{"column name": value}]` (one object per row, empty values omitted) | | Inline blanks | `{"": "..."}` | | Ranking | `[{"rank": 1, "choice": "choice label"}]` | | Reservation | `[{"item_name","scheduled_label","number", ...}]` | | Form association | Display value string of the associated entry | | Association (table) | Array of serial numbers of the linked entries in the associated table, e.g. `[1, 3]`; plus `_related_entries`: `[{"serial_number": 1, "value": "..."}]`, where value is that entry's first-column value | When the request has `include_labels=true`, form field values are wrapped as `{label, value}`. required: - token - serial_number properties: token: type: string description: Unique identifier of the entry serial_number: type: integer created_at: type: string format: date-time updated_at: type: string format: date-time creator_name: type: string color_mark: type: string info_filling_duration: type: number info_platform: type: string info_os: type: string info_browser: type: string info_region: type: object properties: country: type: string province: type: string city: type: string info_remote_ip: type: string additionalProperties: true examples: - token: kjFelJqi serial_number: 36 field_1: 张三 field_3: - 选项 A - 选项 B field_9: 198 field_12: '2021-09-23' creator_name: '' created_at: '2021-09-28T02:59:42.539Z' updated_at: '2021-09-28T02:59:42.539Z' info_filling_duration: 193.51 info_remote_ip: 127.0.0.1 Entry: type: object required: - form - form_name - entry properties: form: type: string description: Form token form_name: type: string entry: $ref: '#/components/schemas/EntryData' url: type: string format: uri description: URL that opens this entry in Jinshuju's data page (the data page for a form, the table page for a table, scrolled to this serial number), for users to check against. Appears only in responses that get, create or update a single entry; list and batch endpoints do not return it; entries of quick payment forms have no such key. examples: - form: kjFelJqi form_name: 报名表 entry: token: kjFelJqi serial_number: 36 field_1: 张三 url: https://next.jinshuju.net/forms/kjFelJqi/entries?serial_number=36 EntryListResponse: type: object required: - total - count - data - next properties: total: type: integer description: Total number of entries matching the conditions count: type: integer description: Number of items on this page data: type: array items: $ref: '#/components/schemas/EntryData' next: type: - integer - 'null' description: Cursor for the next page (the serial number under the default sort, a row offset otherwise); null on the last page EntryInput: type: object description: | Field values for writing an entry, keyed by field api_code or api_code_alias. Unknown keys and non-writable fields (signature, formula) are ignored. Choice fields take the choice api_code or the choice label; see the table below for cascading drop-downs and choice extra text. Number fields accept a number or a numeric string. | Field | How to write | |---|---| | Single-line / multi-line text, name, mobile, email, phone, website, ID card | String | | Single choice, drop-down | `"choice api_code"` or `"choice label"`; extra text via `"_extended_text": {"": "extra text"}`, "Other" text via `"_other": "..."` | | Multiple choice | Array, items as above | | Image single choice / image multiple choice | Choice api_code (string / array) | | Cascading drop-down | `{"level_1": "...", "level_2": "..."}` (api_code or label) | | Number, rating, NPS | Number | | Yes/No | Boolean | | Date | `"2012-12-25"` or `"2012-12-25 12:13:15"` (Beijing time, UTC+8) | | Time | `{"hour": "12", "minute": "15"}` | | Address | `{"province","city","district","street"}` | | Geolocation | `{"longitude","latitude","address"}` | | File upload (multiple allowed) | Array; each item is one of: the id of an uploaded attachment; the download URL of an attachment already on this form (to keep it); `{"base64": "...", "file_name": "a.png", "content_type": "image/png"}` (≤ 5MB; `base64` may also be a data URI); `{"attachment_token": "..."}` (pre-upload token) | | Goods | `[{"value": "goods item api_code", "number": 2, "specification": {"spec dimension": "option"}?}]` | | Matrix fill-in / matrix scale | `{"": {"": value}}` | | Matrix single choice | `{"": "choice api_code"}` | | Table | `[{"": value}, ...]`; attachment columns are written like file upload | | Inline blanks | `{"": "..."}` | | Ranking | Ordered array `["choice api_code", ...]` | | Form association | token / id of the associated entry, or a display value matched by the association key (an array for multiple association keys) | | Reservation | `[{"api_code": "item", "scheduled_at": "2021-04-26", "end_at"?: "...", "number": 1}]` | | Color mark | `"color_mark": ""` | | International mobile number | Also pass `"_country_id"` / `"_country_code"` | additionalProperties: true examples: - field_1: 张三 field_2: '13800000000' field_3: - 选项 A - 选项 B field_4: '2024-05-01' field_5: - 5f3a1b2c4d5e6f7a8b9c0d1e - base64: iVBORw0KGgo... file_name: photo.png content_type: image/png BatchCreateResult: type: object required: - created_count - errors properties: created_count: type: integer errors: type: array items: type: object required: - index - reason properties: index: type: integer description: Index in the request array reason: type: string BatchPatchResult: type: object required: - updated_count - failed_rows properties: updated_count: type: integer failed_rows: type: array items: type: object properties: serial_number: type: - integer - 'null' reason: type: string description: For example `invalid_serial_number`, `invalid_attributes` errors: type: array items: type: string TableSummary: type: object required: - name - token - kind - url - created_at - last_entry_created_at - creator - entries_count properties: name: type: string token: type: string kind: type: string enum: - table url: type: string format: uri description: URL of the table in the product created_at: type: string format: date-time last_entry_created_at: type: - string - 'null' format: date-time creator: $ref: '#/components/schemas/Creator' entries_count: type: integer TableListResponse: type: object required: - total - count - data - next properties: total: type: integer count: type: integer data: type: array items: $ref: '#/components/schemas/TableSummary' next: type: - string - 'null' Table: allOf: - $ref: '#/components/schemas/TableSummary' - type: object required: - fields - views properties: fields: type: array items: $ref: '#/components/schemas/FieldMap' views: type: array description: Views visible to the current identity, in order items: $ref: '#/components/schemas/FormView' FormCreateInput: type: object title: FormCreateInput additionalProperties: false required: - name - fields properties: name: type: string description: Form name description: type: string description: Form description fields: type: array minItems: 1 items: $ref: '#/components/schemas/FieldInput' setting: $ref: '#/components/schemas/FormSettingWriteInput' folder_token: type: string description: Token (or id) of the folder to put it in; you must be able to manage the folder, and its kind must be form scene: type: string enum: - form - survey - registry - vote - exam - reservation - customer_acquisition - evaluation - online_payment - quickpay description: Form scene; a plain form by default layout: type: string enum: - classic - card description: Layout; applies only when scene is survey / form / exam / evaluation; card is the paged layout allOf: - $ref: '#/components/schemas/FormCreateConstraints' TableCreateInput: type: object title: TableCreateInput additionalProperties: false required: - name - fields properties: name: type: string description: Table name description: type: string description: Table description fields: type: array minItems: 1 items: $ref: '#/components/schemas/TableColumnInput' description: Column definitions setting: $ref: '#/components/schemas/FormSettingWriteInput' folder_token: type: string description: Token of the table folder to put it in with_default_entries: type: boolean default: false description: When true, the table starts with 3 blank entries scene: type: string enum: - form - survey - registry - vote - exam - reservation - customer_acquisition - evaluation - online_payment - quickpay FieldInput: type: object description: A form field definition, branched on type; each branch takes only the attributes of that type required: - type - label properties: type: type: string enum: - TextField - TextArea - NumberField - EmailField - MobileField - IdCardField - NameField - RadioButton - CheckBox - DropDown - DateTimeField - RatingField - TableField - TelephoneField - AddressField - AttachmentField - GeoField - LinkField - NpsField - TimeField - SortField - ESignatureField - AudioField - CascadeDropDown - LikertField - MatrixField - MatrixScaleField - GoodsField - FormulaField - ReservationField - FormAssociation - ImageRadioButton - ImageCheckBox - SectionBreak - PageBreak - WidgetButton - WidgetContact - WidgetMap - WidgetMarquee - SingleSelect - MultiSelect - ImageSingleSelect - ImageMultiSelect - TrueOrFalse - DropDownSelect - FillInBlank - ShortAnswer - FillInNumber - Rating - Nps - Department - Grade label: type: string description: Field label discriminator: propertyName: type mapping: TextField: "#/components/schemas/TextFieldInput" TextArea: "#/components/schemas/TextAreaInput" NumberField: "#/components/schemas/NumberFieldInput" EmailField: "#/components/schemas/EmailFieldInput" MobileField: "#/components/schemas/MobileFieldInput" IdCardField: "#/components/schemas/IdCardFieldInput" NameField: "#/components/schemas/NameFieldInput" RadioButton: "#/components/schemas/RadioButtonInput" CheckBox: "#/components/schemas/CheckBoxInput" DropDown: "#/components/schemas/DropDownInput" DateTimeField: "#/components/schemas/DateTimeFieldInput" RatingField: "#/components/schemas/RatingFieldInput" TableField: "#/components/schemas/TableFieldInput" TelephoneField: "#/components/schemas/TelephoneFieldInput" AddressField: "#/components/schemas/AddressFieldInput" AttachmentField: "#/components/schemas/AttachmentFieldInput" GeoField: "#/components/schemas/GeoFieldInput" LinkField: "#/components/schemas/LinkFieldInput" NpsField: "#/components/schemas/NpsFieldInput" TimeField: "#/components/schemas/TimeFieldInput" SortField: "#/components/schemas/SortFieldInput" ESignatureField: "#/components/schemas/ESignatureFieldInput" AudioField: "#/components/schemas/AudioFieldInput" CascadeDropDown: "#/components/schemas/CascadeDropDownInput" LikertField: "#/components/schemas/LikertFieldInput" MatrixField: "#/components/schemas/MatrixFieldInput" MatrixScaleField: "#/components/schemas/MatrixScaleFieldInput" GoodsField: "#/components/schemas/GoodsFieldInput" FormulaField: "#/components/schemas/FormulaFieldInput" ReservationField: "#/components/schemas/ReservationFieldInput" FormAssociation: "#/components/schemas/FormAssociationInput" ImageRadioButton: "#/components/schemas/ImageRadioButtonInput" ImageCheckBox: "#/components/schemas/ImageCheckBoxInput" SectionBreak: "#/components/schemas/SectionBreakInput" PageBreak: "#/components/schemas/PageBreakInput" WidgetButton: "#/components/schemas/WidgetButtonInput" WidgetContact: "#/components/schemas/WidgetContactInput" WidgetMap: "#/components/schemas/WidgetMapInput" WidgetMarquee: "#/components/schemas/WidgetMarqueeInput" SingleSelect: "#/components/schemas/SingleSelectInput" MultiSelect: "#/components/schemas/MultiSelectInput" ImageSingleSelect: "#/components/schemas/ImageSingleSelectInput" ImageMultiSelect: "#/components/schemas/ImageMultiSelectInput" TrueOrFalse: "#/components/schemas/TrueOrFalseInput" DropDownSelect: "#/components/schemas/DropDownSelectInput" FillInBlank: "#/components/schemas/FillInBlankInput" ShortAnswer: "#/components/schemas/ShortAnswerInput" FillInNumber: "#/components/schemas/FillInNumberInput" Rating: "#/components/schemas/RatingInput" Nps: "#/components/schemas/NpsInput" Department: "#/components/schemas/DepartmentInput" Grade: "#/components/schemas/GradeInput" oneOf: - $ref: '#/components/schemas/TextFieldInput' - $ref: '#/components/schemas/TextAreaInput' - $ref: '#/components/schemas/NumberFieldInput' - $ref: '#/components/schemas/EmailFieldInput' - $ref: '#/components/schemas/MobileFieldInput' - $ref: '#/components/schemas/IdCardFieldInput' - $ref: '#/components/schemas/NameFieldInput' - $ref: '#/components/schemas/RadioButtonInput' - $ref: '#/components/schemas/CheckBoxInput' - $ref: '#/components/schemas/DropDownInput' - $ref: '#/components/schemas/DateTimeFieldInput' - $ref: '#/components/schemas/RatingFieldInput' - $ref: '#/components/schemas/TableFieldInput' - $ref: '#/components/schemas/TelephoneFieldInput' - $ref: '#/components/schemas/AddressFieldInput' - $ref: '#/components/schemas/AttachmentFieldInput' - $ref: '#/components/schemas/GeoFieldInput' - $ref: '#/components/schemas/LinkFieldInput' - $ref: '#/components/schemas/NpsFieldInput' - $ref: '#/components/schemas/TimeFieldInput' - $ref: '#/components/schemas/SortFieldInput' - $ref: '#/components/schemas/ESignatureFieldInput' - $ref: '#/components/schemas/AudioFieldInput' - $ref: '#/components/schemas/CascadeDropDownInput' - $ref: '#/components/schemas/LikertFieldInput' - $ref: '#/components/schemas/MatrixFieldInput' - $ref: '#/components/schemas/MatrixScaleFieldInput' - $ref: '#/components/schemas/GoodsFieldInput' - $ref: '#/components/schemas/FormulaFieldInput' - $ref: '#/components/schemas/ReservationFieldInput' - $ref: '#/components/schemas/FormAssociationInput' - $ref: '#/components/schemas/ImageRadioButtonInput' - $ref: '#/components/schemas/ImageCheckBoxInput' - $ref: '#/components/schemas/SectionBreakInput' - $ref: '#/components/schemas/PageBreakInput' - $ref: '#/components/schemas/WidgetButtonInput' - $ref: '#/components/schemas/WidgetContactInput' - $ref: '#/components/schemas/WidgetMapInput' - $ref: '#/components/schemas/WidgetMarqueeInput' - $ref: '#/components/schemas/SingleSelectInput' - $ref: '#/components/schemas/MultiSelectInput' - $ref: '#/components/schemas/ImageSingleSelectInput' - $ref: '#/components/schemas/ImageMultiSelectInput' - $ref: '#/components/schemas/TrueOrFalseInput' - $ref: '#/components/schemas/DropDownSelectInput' - $ref: '#/components/schemas/FillInBlankInput' - $ref: '#/components/schemas/ShortAnswerInput' - $ref: '#/components/schemas/FillInNumberInput' - $ref: '#/components/schemas/RatingInput' - $ref: '#/components/schemas/NpsInput' - $ref: '#/components/schemas/DepartmentInput' - $ref: '#/components/schemas/GradeInput' title: FieldInput ChoiceInput: type: object title: ChoiceInput additionalProperties: false description: A choice; value and name mean the same, give either anyOf: - required: - value - required: - name properties: value: type: string description: Choice label name: type: string description: Same as value api_code: type: string description: The choice api_code; generated by the server when left out, and keeps the identity of the choice on edit quota: type: integer minimum: 1 description: Maximum number of places; leave out for no limit operand_value: type: number description: Numeric value of the choice selected: type: boolean description: Selected by default is_other: type: boolean description: Make this the "Other" choice (choosing it shows a text box); its text is kept as written. A choice whose text is exactly `其他` or `其它` needs no flag. Only for RadioButton / CheckBox / DropDown DimensionInput: type: object title: DimensionInput additionalProperties: false description: A column of a MatrixField or TableField required: - type - label properties: type: type: string enum: - TextField - TextArea - MobileField - CheckBox - DropDown - NumberField - DateTimeField - TimeField - AttachmentField - IdCardField - EmailField description: Column type label: type: string pattern: "\\S" description: Column name api_code: type: string cid: type: string required: type: boolean description: Required choices: type: array items: $ref: '#/components/schemas/ChoiceInput' description: Choices of a choice column StatementInput: type: object title: StatementInput additionalProperties: false required: - label properties: label: type: string pattern: "\\S" description: Statement text api_code: type: string description: Keeps the identity on edit GoodsItemInput: type: object title: GoodsItemInput additionalProperties: false description: A goods item required: - name - layout properties: name: type: string description: Goods name layout: type: string enum: - without_images - price_only - images - text_options description: Layout api_code: type: string description: Keeps the identity of the item on edit; when left out, an existing item is matched by name description: type: string description: Goods description position: type: integer minimum: 0 hidden: type: boolean price: type: number minimum: 0 original_price: type: number minimum: 0 description: Original price, shown struck through predefined_number: type: integer minimum: 0 description: Default quantity fixed_number: type: boolean description: The quantity cannot be changed inventory: type: integer minimum: 0 description: Stock; with specifications, set it on each sku instead inventory_reset: type: boolean min_purchase_quantity: type: integer minimum: 0 max_purchase_quantity: type: integer minimum: 0 dimensions: type: array minItems: 1 items: type: object additionalProperties: false required: - label - options properties: api_code: type: string description: Keeps the identity on edit label: type: string description: Dimension name, such as `尺寸` options: type: array minItems: 1 items: type: object additionalProperties: false required: - label properties: label: type: string value: type: string description: Generated when left out; customized marks a custom amount option description: Specification dimensions skus: type: array minItems: 1 items: type: object additionalProperties: false required: - specification properties: specification: type: object additionalProperties: type: string description: Keyed by dimension api_code or name; each value is an option value or name price: type: number minimum: 0 original_price: type: number minimum: 0 inventory: type: integer minimum: 0 inventory_reset: type: boolean min_purchase_quantity: type: integer minimum: 0 max_purchase_quantity: type: integer minimum: 0 description: Specification combinations; specification must name one option for every dimension image_urls: type: array items: type: string format: uri description: Goods image URLs for layout=images image_base64s: type: array items: type: string description: Base64 goods images for layout=images dependentRequired: dimensions: - skus skus: - dimensions allOf: - description: The price_only / text_options layouts require specifications if: properties: layout: enum: - price_only - text_options then: required: - dimensions - skus - description: The images layout needs at least one image if: properties: layout: const: images then: anyOf: - required: - image_urls properties: image_urls: minItems: 1 - required: - image_base64s properties: image_base64s: minItems: 1 ReservationItemInput: type: object title: ReservationItemInput additionalProperties: false description: A reservation item required: - name properties: name: type: string api_code: type: string description: Keeps the identity of the item on edit; when left out, an existing item is matched by name description: type: string position: type: integer minimum: 0 hidden: type: boolean selected: type: boolean payable: type: boolean description: Requires payment (depends on the plan and the price of each time slot) start_date: type: string format: date end_date: type: string format: date quota_setting: type: object description: Quota settings, branched on type required: - type properties: type: type: string enum: - by_day_repeat_weekly - by_time_range_repeat_daily discriminator: propertyName: type mapping: by_day_repeat_weekly: "#/components/schemas/ReservationByDayQuotaInput" by_time_range_repeat_daily: "#/components/schemas/ReservationByTimeRangeQuotaInput" oneOf: - $ref: '#/components/schemas/ReservationByDayQuotaInput' - $ref: '#/components/schemas/ReservationByTimeRangeQuotaInput' FormSettingWriteInput: type: object description: | The `setting` used when creating / editing a form. Only the keys below are accepted; other keys are ignored. A write describes the resulting state: omitted keys keep their current values, and `null` clears a key. - Passing only `success_message` automatically sets `success_message_style` to `text`; passing only `success_message_rich_text` sets it to `rich_text`. - `submission_region_limited=true` requires a plan that includes "Submission region limit" and at least one item in `submission_regions`. - `merchant_account_id` (小金商户) cannot be bound together with `wxpay_account_id` / `alipay_account_id`; a newly passed payment account must belong to the current account, and once bound, `payment_way` becomes `third_party` automatically. - `notification_rules` replaces all notification rules created through the API as a whole (`[]` clears them); rules created in the desktop UI are not affected. properties: success_message: type: string success_message_rich_text: type: string success_message_style: type: string enum: - text - rich_text entry_submit_mode: type: string success_redirect_url: type: string success_redirect_fields: type: array items: type: string open_entry_action: type: string open_entry_message: type: string open_entry_cancel_reservation: type: boolean show_serial_number_on_success: type: boolean show_submit_again: type: boolean hide_login_and_signup: type: boolean show_close_count_down: type: boolean show_form_before_open: type: boolean manually_close_rule: type: - object - 'null' properties: closed: type: boolean additionalProperties: false by_time_range_close_rule: type: - object - 'null' properties: start_time: type: string format: date-time end_time: type: string format: date-time additionalProperties: false by_entries_close_rule: type: - object - 'null' properties: limit: type: integer additionalProperties: false fill_frequency: type: - object - 'null' description: Accepts only `condition` `fill_type` `cycle_period` `limited_time` `cycles_per_period` `limited_field_api_codes` properties: fill_type: type: string enum: - unlimited - once - repeatable - repeatable_by_day - custom_repeatable condition: type: string enum: - by_weixin - by_ip - by_device - by_fields cycle_period: type: string enum: - every_hour - every_day - every_week - every_month cycles_per_period: type: integer minimum: 1 maximum: 1000 limited_time: type: integer limited_field_api_codes: type: array items: type: string additionalProperties: false show_field_number: type: boolean password_required: type: boolean access_password: type: string allowed_audience: type: string weixin_limited: type: boolean submission_region_limited: type: boolean submission_regions: type: array items: type: string merchant_account_id: type: - string - 'null' wxpay_account_id: type: - string - 'null' alipay_account_id: type: - string - 'null' notification_rules: type: array items: $ref: '#/components/schemas/NotificationRuleInput' daily_repeat_close_rule: $ref: '#/components/schemas/DailyRepeatCloseRuleInput' additionalProperties: false NotificationRuleInput: type: object required: - approach - url properties: approach: type: string enum: - WXWORK - DING_TALK - WEBHOOK description: Notification channel (case-insensitive) url: type: string format: uri description: Bot / webhook URL content: type: string description: Notification content template trigger_scope: type: string default: all_new mentioned_mobile_list: type: array items: type: string enabled: type: boolean default: true additionalProperties: false FormUpdateInput: type: object description: Contains at least one of `name` / `description` / `fields` / `setting` / `field_rules` properties: name: type: string description: type: - string - 'null' setting: $ref: '#/components/schemas/FormSettingWriteInput' fields: type: object description: Incremental field operations; they take effect only when at least one sub-key is non-empty properties: add: type: array description: Fields to add; each may carry `position` (0-based) to set where it is inserted, otherwise it is appended at the end items: anyOf: - $ref: '#/components/schemas/FieldInput' - $ref: '#/components/schemas/TableColumnInput' remove: type: array description: api_codes of the fields to remove; returns 400 when one does not exist items: type: string update: type: array items: $ref: '#/components/schemas/FieldUpdateInput' update_choices: type: array items: $ref: '#/components/schemas/ChoiceUpdateInput' additionalProperties: false field_rules: $ref: '#/components/schemas/FieldRuleOperations' additionalProperties: false FieldUpdateInput: type: object title: FieldUpdateInput additionalProperties: false description: Changes an existing field found by api_code, touching only the keys given. A type-specific attribute is accepted only on a type it applies to (the target type when the type changes); a wrong one is refused with the list of settings that type takes required: - api_code properties: api_code: type: string description: api_code of the field to change type: type: string enum: - TextField - TextArea - NumberField - EmailField - MobileField - IdCardField - NameField - RadioButton - CheckBox - DropDown - DateTimeField - RatingField - TableField - TelephoneField - AddressField - AttachmentField - GeoField - LinkField - NpsField - TimeField - SortField - ESignatureField - AudioField - CascadeDropDown - LikertField - MatrixField - MatrixScaleField - GoodsField - FormulaField - ReservationField - FormAssociation - ImageRadioButton - ImageCheckBox - SectionBreak - PageBreak - WidgetButton - WidgetContact - WidgetMap - WidgetMarquee description: Change the field to this type, keeping its api_code and entries and converting the values; a change that would clear data needs confirm_data_loss confirm_data_loss: type: boolean description: Accept that the type change clears data label: type: string description: Field label notes: type: - string - 'null' description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required unique: type: boolean description: Refuse duplicate values; takes effect only on TextField / NameField / EmailField / MobileField / TelephoneField / IdCardField / LinkField / FormAssociation / TextArea / NumberField other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text; takes effect only on RadioButton / CheckBox / DropDown position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default rating_max: type: integer minimum: 1 choices: type: array items: $ref: '#/components/schemas/CascadeChoiceInput' description: Accepted only for CascadeDropDown, or when a text field changes to a choice type; otherwise use update_choices dimensions: type: array items: $ref: '#/components/schemas/DimensionInput' description: Replaces the whole list statements: type: array items: $ref: '#/components/schemas/StatementInput' description: Replaces the whole list; carry api_code to keep the identity of an item goods_items: type: array items: $ref: '#/components/schemas/GoodsItemUpdateInput' description: Replaces the whole list; carry api_code to keep the identity of an item. An existing item keeps whatever it leaves out, so a reorder lists just the api_codes in the new order reservation_items: type: array items: $ref: '#/components/schemas/ReservationItemInput' description: Replaces the whole list; carry api_code to keep the identity of an item display_field_api_codes: type: array maxItems: 20 items: type: string answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Replaces all the answers answer_setting_mode: type: string enum: - absolute - partial_absolute - relative answer_explanation: type: string calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens minimum_length: type: integer minimum: 0 description: Minimum number of choices; for a LikertField with likert_choice_style=multiple, the minimum per statement maximum_length: type: integer minimum: 0 description: Maximum number of choices; for a LikertField with likert_choice_style=multiple, the maximum per statement predefined_value: description: 'Default value: a string for text fields, a date string matching the precision or today / yesterday / tomorrow for DateTimeField, an {"hour", "minute"} object for TimeField, an address object for AddressField' placeholder: type: string description: Placeholder text sms_verification: type: boolean description: Verify the number by SMS (this also turns on the image captcha) range_min: type: number description: Minimum value, inclusive range_max: type: number description: Maximum value, inclusive precision: anyOf: - type: integer minimum: 0 maximum: 14 - type: string enum: - month - day - minute - second description: Decimal places for NumberField / FormulaField; a precision value for DateTimeField display_precision: type: integer minimum: 0 description: Decimal places shown display_as_percentage: type: boolean description: Show as a percentage; cannot be combined with thousands_separator thousands_separator: type: boolean description: Show a thousands separator; cannot be combined with display_as_percentage currency_symbol: type: string description: Currency symbol currency_symbol_position: type: string enum: - prefix - suffix description: Where the currency symbol goes icon_type: type: string enum: - none - number-2 - dollar1 - cny1 - formula-2 - date-2 - sum - text - text2 description: Field icon changeable: type: object description: 'Which levels of the AddressField can be changed: keys province / city / district / street, boolean values' additionalProperties: type: boolean enable_auto_position: type: boolean description: Fill in the address from the device location when the form first opens max_size: type: integer minimum: 1 maximum: 500 description: Maximum size of one file, in MB max_file_quantity: type: integer minimum: 1 description: Maximum number of files media_type: type: object additionalProperties: false description: 'Allowed file types: type is one preset group, whose extensions x-groups lists, or custom with the extensions listed in value. To allow several groups, write type=custom with the union of their extensions in value' x-groups: doc: - txt - pdf - doc - docx - xls - xlsx - ppt - pptx - wps - rtf - hlp image: - jpg - jpeg - png - gif - bmp - psd - tif - heic - heif video: - mkv - mp4 - avi - swf - wmv - rmvb - mov - mpg audio: - mp3 - flac - ape - wma - wav - aac - m4a - au - ram - mmf - aif compress: - rar - zip - 7z - gz - arj - z properties: type: type: string enum: - unlimited - doc - image - video - audio - compress - custom value: type: array items: type: string description: Lowercase extensions, without the dot if: properties: type: const: custom required: - type then: required: - value properties: value: minItems: 1 mobile_camera_only: type: boolean description: On mobile, only a photo taken with the camera; picking from the photo library is not allowed minimum_ratings_display_text: type: string description: Text shown at the lowest rating maximum_ratings_display_text: type: string description: Text shown at the highest rating include_second: type: boolean description: Include seconds max_duration: type: integer minimum: 1 maximum: 5 description: Maximum recording length, in minutes levels: type: integer minimum: 2 description: Number of levels of the cascading drop-down; every choice path must reach this depth choice_filterable: type: boolean description: Allow filtering the choices horizontal_on_mobile: type: boolean description: Lay out horizontally on mobile likert_choice_style: type: string enum: - single - multiple description: One choice (single) or several (multiple) per statement advanced_feature: type: boolean description: Turn on the advanced features unit: type: string maxLength: 2 description: Unit of quantity, at most 2 characters collapse_on_mobile: type: boolean description: Collapse the goods list on mobile columns_on_mobile: type: integer minimum: 1 description: Goods per row on mobile formula_display: type: string description: The formula as HTML; refer to a field as or result_display_type: type: string enum: - string - numeric - datetime description: How the result is shown result_display_as_date: type: boolean description: Older spelling of result_display_type=datetime allow_multiple_items: type: boolean description: One submission can book several items item_allow_multiple_reservations: type: boolean description: One item can be booked for several time slots allow_multiple_number: type: boolean description: Several places can be booked in one time slot use_daily_time_range: type: boolean description: Use a daily time slot table associated_form_token: type: string description: Token of the associated form associated_field_api_codes: type: array minItems: 1 maxItems: 4 items: type: string description: api_code of the association key fields privacy_safe: type: boolean description: Show the associated fields with privacy masking everywhere allow_reverse_association: type: boolean description: Show the reverse association on the associated form reverse_display_field_api_codes: type: array items: type: string description: api_code of the fields the reverse association shows related_form_token: type: string description: Token of the related table; must be another table, and you need manage permission on it paired: type: boolean description: Two-way relation, on by default; when on, a reverse column is created in the related table related_label: type: string description: Name of the reverse column, used only when the reverse column is created; defaults to the name of this table show_split_line: type: boolean description: Show a divider line show_part_description: type: boolean description: Collapse the description when it is long disable_previous_page: type: boolean description: Hide the "Previous" button previous_page_text: type: string description: Text of the "Previous" button next_page_text: type: string description: Text of the "Next" button count_down: type: integer minimum: 0 description: Seconds the "Next" button stays locked; 0 means not locked buttons_number: type: integer minimum: 1 description: Number of buttons; must equal the length of buttons fixed_to_bottom: type: boolean description: Pin the button bar to the bottom of the page widget_max_images_number: type: integer minimum: 1 description: Maximum number of images shown; at least the length of widget_images phones: type: array description: Contact phone numbers items: type: object required: - phone additionalProperties: false properties: phone: type: string nav_address: type: string description: Address text used for navigation longitude: type: number description: Longitude latitude: type: number description: Latitude value: type: string description: Value shown localizable_on_mobile: type: boolean description: On mobile, allow opening the location in a map lines: type: integer minimum: 1 description: Number of scrolling lines entries_init_number: type: integer minimum: 0 description: Submission count to start from entries_number_visible: type: boolean description: Show the submission count marquee_data_type: type: string enum: - fake - real description: 'Data source: fake for generated data, real for real entries' allOf: - description: display_as_percentage and thousands_separator cannot both be true not: properties: display_as_percentage: const: true thousands_separator: const: true required: - display_as_percentage - thousands_separator - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value ChoiceUpdateInput: type: object required: - field_api_code description: Incremental changes to the choices of a choice field (or of a choice column in a matrix / table field); returns 400 when the field does not exist or does not support choices properties: field_api_code: type: string add: type: array items: $ref: '#/components/schemas/ChoiceInput' remove: type: array description: 'api_code (or choice label) of a choice to remove; can also be written as `{"api_code": "..."}`' items: oneOf: - type: string - type: object properties: api_code: type: string update: type: array items: type: object required: - api_code properties: api_code: type: string value: type: string description: New choice label operand_value: type: number selected: type: boolean additionalProperties: false additionalProperties: false FieldRuleOperations: type: object description: Incremental field display rule operations; `remove` / `update` target a rule by the 0-based `index` that `GET /forms/{form_token}/field_rules` returns; the same index cannot be both removed and updated properties: add: type: array items: $ref: '#/components/schemas/FieldRuleWriteInput' remove: type: array items: type: integer update: type: array items: $ref: '#/components/schemas/FieldRuleWriteInput' additionalProperties: false FieldRuleWriteInput: type: object properties: index: type: integer description: 'Used by update only: index of the rule to change (0-based)' targets: type: array items: type: string description: api_codes of the affected fields; may be omitted when `targets_display_mode=abort` targets_display_mode: type: string enum: - show - abort description: "`show` / `abort`, defaults to show" operator: type: string enum: - or - and description: How the conditions are combined, defaults to or conditions: type: array items: type: object required: - trigger properties: trigger: type: string description: api_code of the trigger field comparator: type: string description: Comparator, defaults to the first one the field supports; an unsupported one returns 400 listing the available comparators value: description: Value to compare with additionalProperties: false additionalProperties: false FormSettingSaveOk: type: object required: - status properties: status: type: string enum: - ok FormSettingSaveFailed: type: object description: Response body when a form settings endpoint fails to save required: - errors - status properties: errors: type: string description: Validation error messages, joined with commas when there are several status: type: string enum: - failed FormFrozenError: type: object description: 403 response body when the form or its creator is frozen required: - errors - status_code properties: errors: description: Freeze reason; an array of strings when the form is frozen, a string when the creator's account is disabled oneOf: - type: string - type: array items: type: string status_code: type: string enum: - form_forbidden ManuallyCloseRule: type: object required: - closed properties: closed: type: boolean description: Whether collection has been closed manually FormManuallyCloseRuleInput: type: object required: - open properties: open: description: true opens collection, false closes it; accepts a boolean or the string "true" / "false" oneOf: - type: boolean - type: string enum: - 'true' - 'false' additionalProperties: false FormFillFrequency: type: object description: Fill frequency limit (read) required: - fill_type - condition - cycle_period - cycles_per_period - limited_time - limited_field_api_codes properties: fill_type: type: string description: Limit type; may be an empty string on legacy data enum: - unlimited - once - repeatable - repeatable_by_day - custom_repeatable - '' condition: type: string description: What identifies the same submitter; an empty string when there is no limit. When unset, the server goes by the signed-in user enum: - by_weixin - by_ip - by_device - by_fields - '' cycle_period: type: string description: Period unit; set only for repeatable / custom_repeatable, otherwise an empty string enum: - every_hour - every_day - every_week - every_month - '' cycles_per_period: type: integer description: Every N periods (takes effect only for custom_repeatable, 1 to 1000) limited_time: type: - integer - 'null' description: Fills allowed per period limited_field_api_codes: type: array description: Fields that identify the submitter when condition is by_fields items: type: string FormFillFrequencyInput: type: object description: Fill frequency limit (write) properties: fill_type: type: string enum: - unlimited - once - repeatable - repeatable_by_day - custom_repeatable description: Limit type; custom_repeatable is a paid feature condition: type: string enum: - by_weixin - by_ip - by_device - by_fields description: What identifies the same submitter; by_fields is a paid feature. Cleared when fill_type is unlimited cycle_period: type: string enum: - every_hour - every_day - every_week - every_month description: Period unit; kept only for repeatable / custom_repeatable cycles_per_period: type: integer minimum: 1 maximum: 1000 description: Every N periods; kept only for custom_repeatable, reset to 1 for the other types limited_time: type: integer minimum: 1 description: Fills allowed per period; must be greater than 0 for repeatable / custom_repeatable limited_field_api_codes: type: array description: Required and cannot be empty when condition is by_fields items: type: string FormSetting: type: object description: Form settings (the response of GET /forms/{form_token}/setting) required: - success_message - success_message_rich_text - success_message_style - entry_submit_mode - success_redirect_url - success_redirect_fields - show_entry_on_success - show_entry_on_success_button_text - edit_entry_on_success - show_serial_number_on_success - show_submit_again - hide_login_and_signup - show_close_count_down - show_form_before_open - manually_close_rule - by_time_range_close_rule - by_entries_close_rule - fill_frequency - password_required - access_password - allowed_audience - weixin_limited - weixin_collect_way - submission_region_limited - submission_regions - entry_post_url - post_new_entry - post_updated_entry - daily_repeat_close_rule properties: success_message: type: - string - 'null' description: Success message (plain text) success_message_rich_text: type: - string - 'null' description: Success message (rich text) success_message_style: type: - string - 'null' enum: - text - rich_text - distribution_poster - certificate - description: Style of the success page entry_submit_mode: type: string enum: - show_message - redirect - reports - exam_score description: What happens after submission success_redirect_url: type: - string - 'null' description: URL to redirect to after submission success_redirect_fields: type: array description: api_codes of the fields appended to the redirect items: type: string show_entry_on_success: type: - boolean - 'null' show_entry_on_success_button_text: type: - string - 'null' edit_entry_on_success: type: - boolean - 'null' show_serial_number_on_success: type: - boolean - 'null' show_submit_again: type: - boolean - 'null' hide_login_and_signup: type: - boolean - 'null' show_close_count_down: type: - boolean - 'null' description: Show a countdown before closing show_form_before_open: type: - boolean - 'null' description: Whether to show the form before it opens manually_close_rule: type: - object - 'null' description: Manual closing rule; null when not set properties: closed: type: boolean by_time_range_close_rule: type: - object - 'null' description: Time-range opening rule; null when not set properties: start_time: type: - string - 'null' format: date-time end_time: type: - string - 'null' format: date-time by_entries_close_rule: type: - object - 'null' description: Entry-count closing rule; null when not set properties: limit: type: - integer - 'null' fill_frequency: description: Fill frequency limit; null when not set oneOf: - type: 'null' - $ref: '#/components/schemas/FormFillFrequency' password_required: type: - boolean - 'null' description: Whether a password is required to fill in access_password: type: - string - 'null' description: Fill password (returned in plain text) allowed_audience: type: string enum: - public - internal - private - weixin_qiye_followers_only - weixin_followers_only - submitter_only - gd_user_only description: Who is allowed to fill in weixin_limited: type: - boolean - 'null' description: Fill in only inside WeChat weixin_collect_way: type: string enum: - not_collect - goldendata - own - own_weixin_qiye - yamcha description: How WeChat user info is collected submission_region_limited: type: - boolean - 'null' description: Whether submission regions are limited (read-only) submission_regions: type: array description: Regions allowed to submit (read-only) items: type: string entry_post_url: type: - string - 'null' description: Webhook push URL post_new_entry: type: - boolean - 'null' description: Whether new entries are pushed post_updated_entry: type: - boolean - 'null' description: Whether entry updates are pushed weixin: type: object description: The WeChat Official Account chosen for the form; returned only when one is configured required: - appid - scope properties: appid: type: string scope: type: string enum: - base - userinfo description: WeChat web authorization scope component_appid: type: string description: Third-party appid on the WeChat Open Platform; omitted when absent daily_repeat_close_rule: $ref: '#/components/schemas/DailyRepeatCloseRule' FormSettingInput: type: object description: Request body of PATCH /forms/{form_token}/setting; only the keys present are written properties: success_message: type: string maxLength: 2000 success_message_rich_text: type: string description: Rich text; embedded iframe domains must be on the allowlist success_message_style: type: string enum: - text - rich_text - distribution_poster - certificate description: distribution_poster requires form distribution to be on, certificate requires certificates to be on enable_qrcode: type: boolean description: Whether the success page shows a QR code (not echoed in the GET response) entry_submit_mode: type: string enum: - show_message - redirect - reports - exam_score success_redirect_url: type: string description: Must be a valid URL when entry_submit_mode is redirect success_redirect_fields: type: array description: api_codes of the fields appended to the redirect; how many is limited by the plan quota items: type: string show_entry_on_success: type: boolean show_entry_on_success_button_text: type: string edit_entry_on_success: type: boolean show_serial_number_on_success: type: boolean show_submit_again: type: boolean hide_login_and_signup: type: boolean show_close_count_down: type: boolean show_form_before_open: type: boolean show_field_number: type: boolean description: Whether to show field numbers (not echoed in the GET response) password_required: type: boolean description: When true, access_password is required as well; when false, the server clears the password access_password: type: string description: Only ASCII letters, digits and common symbols are allowed allowed_audience: type: string enum: - public - internal - private - weixin_qiye_followers_only - weixin_followers_only - submitter_only - gd_user_only weixin_limited: type: boolean entry_post_url: type: string description: Webhook push URL; must be a valid URL post_new_entry: type: boolean post_updated_entry: type: boolean manually_close_rule: type: object description: Manual closing rule; when closed changes, the server deletes the other closing rules properties: closed: type: boolean additionalProperties: false by_time_range_close_rule: type: object description: Open during a time range; at least one of start_time / end_time, and end_time not earlier than start_time properties: start_time: type: - string - 'null' format: date-time end_time: type: - string - 'null' format: date-time additionalProperties: false by_entries_close_rule: type: object description: Close once a given number of entries is collected properties: limit: type: integer additionalProperties: false fill_frequency: $ref: '#/components/schemas/FormFillFrequencyInput' additionalProperties: false AccessPolicyInput: type: object description: Request body of PATCH /forms/{form_token}/access_policy properties: fill_frequency: $ref: '#/components/schemas/FormFillFrequencyInput' additionalProperties: false WebhookInput: type: object properties: entry_post_url: type: string description: URL that entries are pushed to additionalProperties: false FormWebhook: type: object required: - entry_post_url properties: entry_post_url: type: - string - 'null' FieldRule: type: object description: One field display rule required: - index - targets - targets_display_mode - operator - conditions properties: index: type: integer description: 0-based position, used by PATCH /forms/{form_token} to update or remove the rule targets: type: array description: api_codes of the controlled fields; always ["DYNAMIC_TARGETS"] when targets_display_mode is abort items: type: string targets_display_mode: type: string enum: - show - abort description: 'show: show the target fields when the conditions are met; abort: end the fill when the conditions are met' operator: type: string enum: - or - and description: Logical relation between the conditions conditions: type: array items: type: object required: - trigger - comparator - value properties: trigger: type: string description: api_code of the trigger field comparator: type: string enum: - equal - none_in - between - like - not_like description: equal means "contains any of" (for historical reasons) value: description: 'Condition value: an array of choice api_codes, a numeric range [min, max] or text, depending on the trigger field''s type' ExtendedAttribute: type: object required: - value - url - cname - created_at properties: value: type: string description: Extended attribute value url: type: string format: uri description: Fill link carrying this value cname: type: boolean description: Whether the link uses a custom domain created_at: type: - string - 'null' format: date-time IntervalComment: type: object description: One score-range comment; keys whose value is null are omitted properties: start_point: type: number description: Range start, inclusive end_point: type: number description: Range end, inclusive; not less than start_point comment: type: string description: Comment text (rich text) retry: type: boolean description: Whether retaking is allowed FormIntervalCommentInput: type: object properties: start_point: type: number end_point: type: number description: Not less than start_point comment: type: string retry: type: boolean ExamSetting: type: object description: Exam settings; an empty object when the form has no exam settings record yet. Keys whose value is null are omitted properties: notice_after_filling_mode: type: string enum: - appreciation - grade - explaination - none - answer description: What to show after the exam is handed in show_timeout: type: boolean description: Whether the exam is timed limited_time: type: integer description: Time limit in minutes need_attention: type: string description: Instructions shown before the exam interval_comments: type: array description: Score-range comments; returned only when score-range comments are on items: $ref: '#/components/schemas/IntervalComment' ExamSettingInput: type: object description: Request body of PATCH /forms/{form_token}/exam_setting; only the keys present are written properties: notice_after_filling_mode: type: string enum: - appreciation - grade - explaination - none - answer description: Forced to none when the plan does not support showing scores show_timeout: type: boolean description: 'Turns on the exam time limit. Mutually exclusive with required on exam question fields: passing true returns 400 when the form already has a required question; once on, question fields can no longer be set as required (required on examinee info fields is unaffected)' limited_time: type: integer minimum: 1 maximum: 9999 description: Time limit in minutes need_attention: type: string success_message_rich_text: type: string description: Rich-text message shown after the exam is handed in; written only when the plan supports showing scores interval_comments: type: array description: Replaces the score-range comments as a whole; ranges must not overlap. Takes effect only when notice_after_filling_mode is grade / explaination / answer; an empty array is ignored items: $ref: '#/components/schemas/FormIntervalCommentInput' additionalProperties: false CheckinDateSetting: type: object description: A date range check-in is open in. Check-in works on the days within the range that fall on `periods`, inside the duration. For several durations, pass several date_settings required: - start_date - end_date - periods - durations properties: start_date: type: string format: date end_date: type: string format: date periods: type: array minItems: 1 description: Weekdays check-in is open on; list all seven for every day items: type: string enum: - Monday - Tuesday - Wednesday - Thursday - Friday - Saturday - Sunday durations: type: array minItems: 1 maxItems: 1 description: The time of day check-in is open; exactly one items: type: object required: - start - end properties: start: type: string pattern: "^([01][0-9]|2[0-3]):[0-5][0-9]$" description: Start time, HH:MM end: type: string pattern: "^([01][0-9]|2[0-3]):[0-5][0-9]$" description: End time, HH:MM additionalProperties: false additionalProperties: false CheckinGeoLocation: type: object description: Location limit; check-in works only within `range` meters of the coordinates required: - longitude - latitude - range properties: location_name: type: string address: type: string longitude: type: number latitude: type: number range: type: integer minimum: 1 description: Radius check-in is allowed in, in meters additionalProperties: false CheckinCampaign: type: object description: Check-in campaign properties: id: type: integer name: type: string form_token: type: string description: The form it is bound to enabled: type: boolean description: Whether it is in effect checkin_field_api_code: type: string description: Field registrants check in with (usually the mobile number), matched against their entries display_field_api_code: type: - string - 'null' description: Field shown when verifying (usually the name) enable_checkin_code: type: boolean description: Whether submitting goes on to the check-in code page date_settings: type: array description: When check-in is open; empty means any time items: $ref: '#/components/schemas/CheckinDateSetting' geo_location: description: Location limit; null means anywhere oneOf: - type: 'null' - $ref: '#/components/schemas/CheckinGeoLocation' checkin_count: type: integer description: How many have checked in checkin_url: type: string description: Link registrants scan to check themselves in verifier_invite_url: type: string description: Link that invites a verifier, who can then verify check-ins on site manage_url: type: string description: Page that manages the campaign in Jinshuju created_at: type: string format: date-time updated_at: type: string format: date-time CheckinCampaignCreateInput: type: object title: CheckinCampaignCreateInput description: Request body of POST /plugins/checkin/campaigns required: - form_token properties: form_token: type: string description: The form to turn check-in on for checkin_field_api_code: type: string description: Check-in field; defaults to the first mobile field, then the first name field. Cannot be changed afterwards name: type: string minLength: 1 description: Campaign name; the form name by default display_field_api_code: type: - string - 'null' description: Field shown when verifying, not the check-in field; null clears it enable_checkin_code: type: boolean description: After submitting, go on to the check-in code page; registrants show the code on site checkin_field_required_unique: type: boolean description: true makes the check-in field required and unique, so no registrant is left unable to check in date_settings: type: array description: Replaces the check-in times as a whole; an empty list means any time items: $ref: '#/components/schemas/CheckinDateSetting' geo_location: description: Sets the location limit; null lifts it oneOf: - type: 'null' - $ref: '#/components/schemas/CheckinGeoLocation' additionalProperties: false CheckinCampaignUpdateInput: type: object title: CheckinCampaignUpdateInput description: Request body of PATCH /plugins/checkin/campaigns/{id}; only the keys present are written properties: enabled: type: boolean description: false pauses check-in and unbinds it from the form; true turns it back on name: type: string minLength: 1 description: Campaign name display_field_api_code: type: - string - 'null' description: Field shown when verifying, not the check-in field; null clears it enable_checkin_code: type: boolean description: After submitting, go on to the check-in code page; registrants show the code on site checkin_field_required_unique: type: boolean description: true makes the check-in field required and unique, so no registrant is left unable to check in date_settings: type: array description: Replaces the check-in times as a whole; an empty list means any time items: $ref: '#/components/schemas/CheckinDateSetting' geo_location: description: Sets the location limit; null lifts it oneOf: - type: 'null' - $ref: '#/components/schemas/CheckinGeoLocation' additionalProperties: false EvaluationComment: type: object description: | One total-score range comment. A comment written by score range returns start_point / end_point; a comment written by conditions in the form editor returns id and conditions instead (no start_point / end_point). Keys whose value is null are omitted properties: start_point: type: number end_point: type: number comment: type: string retry: type: boolean id: type: string description: id of a condition-based comment; pass this id back when updating conditions: type: array description: Conditions of a condition-based comment items: type: object properties: trigger: type: string description: api_code of the condition field operator: type: string description: Comparison operator value: description: Condition value group_index: type: integer FormEvaluationCommentInput: type: object description: A range-based comment needs both start_point and end_point; a condition-based comment is passed back by the id it was read with, and only comment / retry can change properties: id: type: string description: id of a condition-based comment conditions: type: array description: May be passed back as is; cannot be changed items: type: object properties: trigger: type: string operator: type: string value: description: Condition value group_index: type: integer start_point: type: number end_point: type: number comment: type: string retry: type: boolean EvaluationSetting: type: object description: Evaluation settings; an empty object when the form has no evaluation settings record yet. Keys whose value is null are omitted properties: notice_after_filling_mode: type: string enum: - reports - customize - none description: What to show after submission show_report_score: type: boolean description: Show the total score in the report show_report_radar: type: boolean description: Show the radar chart in the report show_indicator_comments: type: boolean description: Show the dimension comments in the report show_comments: type: boolean description: Show the total-score comments in the report need_attention: type: string description: Instructions shown before the evaluation evaluation_comments: type: array description: Total-score range comments; returned only when they are on items: $ref: '#/components/schemas/EvaluationComment' indicator_setting: type: object description: Dimension settings; returned only when dimensions exist properties: indicators_scoring_mode: type: string enum: - summation - average - customization description: How dimensions are scored indicators: type: array items: type: object properties: api_code: type: string description: Dimension identifier; the dimension score in an entry is stored under indicator_ name: type: string field_api_codes: type: array items: type: string standard_score: type: number description: Standard score; omitted when null indicator_comments: type: array items: $ref: '#/components/schemas/IntervalComment' EvaluationSettingInput: type: object description: Request body of PATCH /forms/{form_token}/evaluation_setting; only the keys present are written properties: notice_after_filling_mode: type: string enum: - reports - customize - none description: Forced to none when the plan does not support evaluation reports show_report_score: type: boolean show_report_radar: type: boolean show_indicator_comments: type: boolean show_comments: type: boolean need_attention: type: string success_message_rich_text: type: string evaluation_comments: type: array description: Replaces the total-score range comments as a whole; an empty array turns range comments off. Ranges must not overlap items: $ref: '#/components/schemas/FormEvaluationCommentInput' indicator_setting: type: object description: Dimension settings; indicators is replaced as a whole properties: enabled: type: boolean default: true indicators_scoring_mode: type: string enum: - summation - average - customization default: summation indicators: type: array maxItems: 200 items: type: object required: - name properties: api_code: type: string description: Pass back an existing dimension's api_code to keep its identity; omit it for a new dimension name: type: string maxLength: 20 standard_score: type: number field_api_codes: type: array description: api_codes of the bound questions; each must be a visible, scorable question on the form items: type: string field_cids: type: array description: Questions can also be referenced by cid (a number or a string) items: oneOf: - type: string - type: integer indicator_comments: type: array maxItems: 20 description: Dimension range comments (retry is not supported) items: type: object properties: start_point: type: number end_point: type: number comment: type: string additionalProperties: false additionalProperties: false additionalProperties: false additionalProperties: false Cooperator: type: object required: - user_id - name - role properties: user_id: type: string description: User id name: type: string description: User display name role: type: - string - 'null' description: Role name FormWeixinOauthSessionInput: type: object required: - code properties: code: type: string description: code returned by the WeChat web authorization callback additionalProperties: false FormWeixinOauthSession: type: object required: - openid properties: openid: type: string unionid: type: string description: Present only for the userinfo scope and when WeChat returns it profile: type: object description: Present only for the userinfo scope properties: nickname: type: - string - 'null' headimgurl: type: - string - 'null' sex: type: integer description: 'WeChat gender value: 0 unknown / 1 male / 2 female' country: type: - string - 'null' province: type: - string - 'null' city: type: - string - 'null' ThemeInput: type: object description: Request body of PATCH /forms/{form_token}/theme; contains at least one theme operation key properties: primary_color: type: string description: Primary color, e.g. "#FBBF24" secondary_color: type: string description: Secondary color wallpaper: type: object description: Page background properties: background_color: type: string background_image_url: type: string description: The server fetches this URL and uses it as the background image background_image_upload_token: type: string description: The `form_image_token` used by "Upload a form image"; the image purpose must be wallpaper; takes precedence over background_image_url background_image_attachment_id: type: - string - 'null' description: attachment_id returned by "Upload a form image" (image_type=wallpaper); an empty string removes the current background image. Lower priority than background_image_upload_token / background_image_url additionalProperties: false header: type: object description: Header properties: type: type: string enum: - none - text - image - carousel text: type: string description: Header text background_color: type: string text_style: type: object description: Text style; keys use underscores (e.g. font_size, text_align) and are merged into the existing style additionalProperties: type: string header_image_url: type: string description: The server fetches this URL and uses it as the header image header_image_base64: type: string description: Base64-encoded header image; takes precedence over header_image_url header_image_upload_token: type: string description: The `form_image_token` used by "Upload a form image"; the image purpose must be header; highest priority carousel_images: type: array minItems: 1 maxItems: 5 description: Carousel images; replaced as a whole and shown in array order items: type: object description: Provide one of image_upload_token / image_url / attachment_id properties: image_upload_token: type: string description: The `form_image_token` used by "Upload a form image"; the image purpose must be carousel image_url: type: string attachment_id: type: string description: Keeps an existing carousel image of this form additionalProperties: false header_image_attachment_id: type: - string - 'null' description: attachment_id returned by "Upload a form image" (image_type=header); an empty string removes the current header image. Lowest priority; header.type is set to image when not given additionalProperties: false typography: type: object description: Typography; keys use underscores and are merged into the existing style properties: form_header: type: object additionalProperties: type: string field_label: type: object additionalProperties: type: string choice_style: type: object additionalProperties: type: string additionalProperties: false form_container: type: object properties: background_color: type: string border_color: type: string description: Border color of the form container, e.g. "#E5E7EB" border_width: type: string description: Border width of the form container, e.g. "1px" additionalProperties: false submit_button: type: object properties: background_color: type: string color: type: string font_size: type: string description: e.g. "16px" additionalProperties: false generate_header_image: type: object description: Generates a header image with AI and sets it as the header image; uses AI points properties: prompt: type: string description: Prompt for the image; when omitted, AI writes one from the form's content additionalProperties: false additionalProperties: false FormTheme: type: object description: Response after the theme is updated required: - form_token - primary_color - secondary_color - wallpaper - header - typography - form_container - submit_button properties: form_token: type: string primary_color: type: - string - 'null' secondary_color: type: - string - 'null' wallpaper: type: object properties: background_color: type: - string - 'null' has_background_image: type: boolean background_image_url: type: - string - 'null' header: type: object properties: type: type: - string - 'null' enum: - none - text - image - carousel - text: type: - string - 'null' text_style: type: - object - 'null' description: CSS hyphenated keys additionalProperties: true background_color: type: - string - 'null' has_header_image: type: boolean header_image_url: type: - string - 'null' carousel_images: type: array items: type: object required: - attachment_id - image_url properties: attachment_id: type: string image_url: type: string typography: type: object properties: form_header: type: - object - 'null' additionalProperties: true field_label: type: - object - 'null' additionalProperties: true choice_style: type: - object - 'null' additionalProperties: true field_space: type: - string - 'null' form_container: type: object properties: background_color: type: - string - 'null' max_width: type: - string - 'null' border_color: type: - string - 'null' border_width: type: - string - 'null' shadow: type: boolean indent_on_large_phone: type: boolean submit_button: type: object properties: background_color: type: - string - 'null' color: type: - string - 'null' font_size: type: - string - 'null' shadow: type: boolean hidden: type: boolean FormFolderMoveInput: type: object required: - folder_token properties: folder_token: type: - string - 'null' description: Target folder token; null moves the form out of its folder additionalProperties: false FormFolderMoveResult: type: object required: - form_token - folder_token properties: form_token: type: string folder_token: type: - string - 'null' description: Token of the folder it is in after the move; null when moved out of folders CopyFormInput: type: object properties: name: type: string description: Name of the new form; when omitted, the server's default naming applies folder_token: type: string description: Target folder token or id; when omitted, the copy is not put in a folder additionalProperties: false UploadedFormImage: type: object required: - attachment_id properties: attachment_id: type: string description: Image attachment ID (see "Upload a form image") url: type: string description: Image URL, returned only when `image_type=description`; put it in the `` of a form description or field description UploadedEntryAttachment: type: object required: - id - file_name - content_type - file_size - download_url properties: id: type: string description: Attachment ID; put it in an attachment field when creating / updating an entry file_name: type: string description: File name content_type: type: string description: MIME type file_size: type: integer description: File size in bytes download_url: type: string description: Download URL (long-lived) preview_url: type: string description: Image preview URL; returned only for image attachments UploadedImportFile: type: object required: - id - file_name - content_type - file_size properties: id: type: string description: Import attachment ID; pass it as `attachment_id` to "Import entries from an uploaded spreadsheet" file_name: type: string description: File name content_type: type: - string - 'null' description: MIME type file_size: type: integer description: File size in bytes EntryAttachmentBase64Input: type: object required: - field_api_code - base64 properties: field_api_code: type: string description: api_code of the attachment field; for an attachment column in a table field, pass the table field's api_code dimension_api_code: type: string description: api_code of the attachment column in a table field; required when `field_api_code` is a table field attachment_token: type: string description: One-time upload token, starting with `entry_att_tok_`; when passed, it replaces the regular credentials base64: type: string description: File content as a Base64 string, optionally with a `data:;base64,` prefix, at most 5 MB once decoded; the `data` key also works data: type: string description: Alias of `base64` file_name: type: string description: File name, defaults to `attachment`; the `filename` key also works filename: type: string description: Alias of `file_name` content_type: type: string description: MIME type, defaults to the one in the data URI prefix, otherwise `application/octet-stream` additionalProperties: false Folder: type: object required: - token - name - kind - created_at properties: token: type: string description: Folder token name: type: string description: Folder name kind: type: - string - 'null' enum: - form - table - quickpay - description: 'Folder kind: `form` holds forms, `table` holds tables; form folders created early on may have null, which is treated as `form`' created_at: type: string format: date-time description: Created at (UTC) FolderInput: type: object required: - name properties: name: type: string minLength: 1 description: Folder name, cannot be empty kind: type: - string - 'null' enum: - form - table - default: form description: Folder kind; a folder holds one kind of content only, and tables go only into `table` folders. Defaults to `form` additionalProperties: false PredefinedChoicesSet: type: object required: - id - label - type - choices properties: id: type: string description: Choice set ID label: type: string description: Choice set name type: type: string enum: - global - custom description: Choice set type; this endpoint returns only custom, the account's own sets choices: type: array description: Choices items: type: object required: - label properties: label: type: string description: Choice text PredefinedChoicesSetInput: type: object required: - label - choices properties: label: type: string description: Choice set name, cannot be empty choices: type: array description: List of choice texts; empty strings are dropped, and the list cannot be empty after that items: type: string additionalProperties: false PredefinedChoicesSetError: type: object required: - errors - status properties: errors: type: string description: Error message; multiple validation messages are joined with `; ` status: type: string enum: - failed TemplateUsageInput: type: object required: - id properties: id: type: string description: Template token or 24-character hex ID; the `template_id` key also works template_id: type: string description: Alias of `id` tags: description: Tags for the new form, as an array or a comma-separated string oneOf: - type: array items: type: string - type: string tag_id: type: string description: ID of the tag to file the new form under folder_id: type: string description: ID of the folder to put the new form in scene: type: string description: Target scene key; falls back to form when the template's fields go beyond what that scene allows frm: type: string description: Source marker; when it starts with `spread` or is `scene_creation_modal`, it affects the recorded created_from create_source: type: string description: Creation source marker (defined by the server implementation) group_id: type: string description: Group parameter appended to `success_url` form_app_trial_alert: type: boolean description: When true, first checks whether the form app bound to the template needs a purchase / trial; if it does, returns 200 with `error` confirm_unbind_form_app: type: boolean description: Confirms unbinding the form app that needs a purchase, then goes on creating the form confirm_form_app_trial: type: boolean description: Confirms starting the form app trial, then goes on creating the form Contact: type: object required: - id - name - emails - phones properties: id: type: string description: Contact ID name: type: - string - 'null' description: Name emails: type: array description: Emails items: type: string phones: type: array description: Mobile numbers items: type: string CurrentUser: type: object required: - id - name - email - mobile - role - billing_account_id - created_at properties: id: type: string description: User ID name: type: - string - 'null' description: Display name email: type: - string - 'null' description: Email mobile: type: - string - 'null' description: Mobile number role: type: string enum: - owner - admin - worker - outworker description: Role in the account billing_account_id: type: string description: ID of the account the user belongs to created_at: type: string format: date-time description: Signed up at (UTC) BillingAccountUser: type: object required: - id - name - email - mobile - role - status - created_at properties: id: type: string description: User ID name: type: - string - 'null' description: Display name email: type: - string - 'null' description: Email mobile: type: - string - 'null' description: Mobile number role: type: string enum: - owner - admin - worker - outworker description: Role in the account status: type: string enum: - active - disabled description: Member status created_at: type: string format: date-time description: Joined at (UTC) BillingAccount: type: object required: - id - name - subdomain - users_count - plan - usage - feature_trial - merchant_accounts - wxpay_accounts - alipay_accounts properties: id: type: string description: Account ID name: type: - string - 'null' description: Account name subdomain: type: - string - 'null' description: Custom subdomain users_count: type: integer description: Number of active members plan: type: object required: - code - name - end_date - org_plan - expired properties: code: type: string description: Plan code (e.g. free, pro2, ent2, e10, e20, e30, en_cor) name: type: string description: Plan name end_date: type: string description: Plan end date (YYYY-MM-DD); an empty string when there is no end date org_plan: type: boolean description: Whether it is an organization plan expired: type: boolean description: Whether the organization plan has expired usage: type: - object - 'null' description: Usage this month; keys are add-on service codes (sms, active_mail, entry_quota, storage_quota, ai_points, audio_quota, entry_transaction_quota, merchant_entry_transaction_quota) required: - next_reset_date properties: next_reset_date: type: string description: Next usage reset date (YYYY-MM-DD) additionalProperties: $ref: '#/components/schemas/BillingAccountUsageItem' feature_trial: type: object required: - in_use - expired - label - end_date properties: in_use: type: boolean description: Whether a feature trial is in progress expired: type: boolean description: Whether the feature trial has ended label: type: - string - 'null' description: Name of the trial plan end_date: type: string description: Trial end date (YYYY-MM-DD); an empty string when no trial has been taken merchant_accounts: type: array description: Bound payment merchants items: type: object required: - id - name - merchant_no - channels properties: id: type: string name: type: - string - 'null' merchant_no: type: - string - 'null' description: Merchant number channels: type: array description: Enabled payment channels (wxpay / alipay) items: type: string wxpay_accounts: type: array description: Bound WeChat Pay accounts items: type: object required: - id - mch_id - mch_name properties: id: type: string mch_id: type: - string - 'null' mch_name: type: - string - 'null' alipay_accounts: type: array description: Bound Alipay accounts items: type: object required: - id - email - account_type properties: id: type: string email: type: - string - 'null' account_type: type: - string - 'null' enum: - create_direct_pay_by_user - create_partner_trade_by_buyer - trade_create_by_buyer - fast_instant_trade_pay - BillingAccountUsageItem: type: object description: Quota and usage of one add-on service; when the quota is unlimited, only unit, unlimited and consumed_quota are present required: - unit - consumed_quota properties: unit: type: string enum: - item - mb - second - cent description: Unit of measure unlimited: type: boolean description: true when the quota is unlimited total_quota: type: integer description: Total quota this month (included in the plan + purchased) total_balance: type: integer description: Total remaining quota month_balance: type: integer description: Remaining part of this month's plan-included quota consumed_quota: type: integer description: Consumed this month ViewUnprocessableError: type: object required: - error_description properties: error_description: type: string description: Error description; multiple validation errors are joined with commas FormViewSortRule: type: object required: - api_code properties: api_code: type: string description: api_code of the sort field order: type: string enum: - asc - desc default: asc description: Sort direction FormViewFilterCondition: type: object required: - field - operator properties: field: type: string description: Field api_code (api_code / trigger are also accepted as the key name) operator: type: string description: 'Operator, the same as the entry list filters: eq, ne, any_in, none_in, between, not_between, null, not_null, gte, gt, lte, lt, like, not_like, match, within_last; the aliases start / end / equal / not_equal are equivalent to gte / lte / eq / ne respectively. The server decides which subset each field type supports. On choice fields, eq / ne are saved as any_in / none_in and the value is turned into an array.' value: description: 'Condition value; its type depends on the field and the operator: a two-element array for between; {"unit": "day", "n": 30} for within_last (unit can be minute / day / week / month); on choice fields, pass choice api_codes or choice texts, with "null" meaning not filled in; null / not_null take no value.' FormView: type: object required: - token - name - view_type - position - predefined - visibility - view_scope - prefer_columns - sorted_columns - kanban_group_by_api_code - kanban_card_title_api_code - kanban_group_order - kanban_hidden_groups - grid_frozen_boundary_api_code - sort - filter - created_at - updated_at properties: token: type: string description: View token name: type: string description: View name view_type: type: string enum: - grid - kanban - stats - form description: View type; form is a form view (a public fill page, tables only) position: type: integer description: Position in the order of views predefined: type: boolean description: Whether it is a predefined view (cannot be deleted) visibility: type: string enum: - cooperators - personal description: 'Visibility: cooperators means visible to all cooperators, personal means visible only to the creator' view_scope: type: string enum: - user - form description: What the view belongs to; form means it belongs to the form itself (cannot be deleted, and its visibility cannot be switched) prefer_columns: type: array description: api_codes of the fields shown items: type: string sorted_columns: type: array description: Column display order, by position ascending items: type: object required: - api_code - position properties: api_code: type: string description: Field api_code position: type: integer description: Column position, starting at 1 kanban_group_by_api_code: type: - string - 'null' description: api_code of the kanban grouping field kanban_card_title_api_code: type: - string - 'null' description: api_code of the kanban card title field; when not set, the server derives it from prefer_columns kanban_group_order: type: array description: Display order of kanban groups (api_codes of the grouping choices; `__unset__` means no group set) items: type: string kanban_hidden_groups: type: array description: Hidden kanban groups (same values as kanban_group_order) items: type: string grid_frozen_boundary_api_code: type: - string - 'null' description: api_code of the field at the frozen-column boundary in a grid view sort: type: array description: Sort rules items: type: object required: - api_code - order properties: api_code: type: string description: api_code of the sort field order: type: string enum: - asc - desc description: Sort direction filter: type: array description: Filters; an empty array when there are none items: $ref: '#/components/schemas/FormViewFilterCondition' created_at: type: string format: date-time description: Created at updated_at: type: string format: date-time description: Updated at title: type: - string - 'null' description: Fill page title (returned for form views only) description: type: - string - 'null' description: Fill page description (returned for form views only) published: type: boolean description: Whether it is published; the fill link does not work while unpublished (returned for form views only) fill_url: type: string format: uri description: Public fill link (returned for form views only) fill_items: type: array description: Fill items checked on the fill page, in fill page order, with their effective values (returned for form views only) items: $ref: '#/components/schemas/FormViewFillItem' FormViewInput: type: object description: Request body to create / update a view; only the keys present are updated properties: name: type: string maxLength: 120 description: View name, cannot be empty view_type: type: string enum: - grid - kanban - stats - form description: View type, defaults to grid on create; form is a form view (a public fill page), supported by tables only visibility: type: string enum: - cooperators - personal description: Visibility, defaults to cooperators on create; on update only the creator can switch it prefer_columns: type: array description: api_codes of the fields shown items: type: string kanban_group_by_api_code: type: string description: api_code of the kanban grouping field; must be a field that supports kanban grouping kanban_card_title_api_code: type: string description: api_code of the kanban card title field kanban_group_order: type: array description: Display order of kanban groups; elements must be non-empty, unique strings items: type: string kanban_hidden_groups: type: array description: Hidden kanban groups; elements must be non-empty, unique strings; an empty array shows all groups items: type: string sort: type: array description: Sort rules, replaced as a whole items: $ref: '#/components/schemas/FormViewSortRule' sorted_columns: type: array description: Column display order, replaced as a whole; position is generated from 1 in array order items: type: object required: - api_code properties: api_code: type: string description: Field api_code additionalProperties: false filter: type: array description: Array of filters, replaced as a whole; an empty array clears the filters; returns 422 when it is not an array items: $ref: '#/components/schemas/FormViewFilterCondition' title: type: string maxLength: 120 description: Fill page title, cannot be empty; defaults to the table name on create. Form views (view_type=form) only; on other view types it returns 422. description: type: - string - 'null' description: Fill page description. Form views (view_type=form) only; on other view types it returns 422. published: type: boolean description: Whether the fill page is published, defaults to false on create. Form views (view_type=form) only; on other view types it returns 422. field_overrides: type: array description: Fill item settings, replaced as a whole; when omitted on create, every fillable column is checked in the current column order. Form views (view_type=form) only; on other view types it returns 422. items: $ref: '#/components/schemas/FormViewFieldOverrideInput' cid: type: string description: Client identifier, passed through in the real-time change broadcast (defined by the server implementation) additionalProperties: false EntryCommentMention: type: object required: - user_id - user_name properties: user_id: type: string description: id of the mentioned user user_name: type: string description: Display name of the mentioned user at the time of the mention EntryCommentAttachment: type: object required: - id - file_name - content_type - file_size - url properties: id: type: string description: Attachment id file_name: type: string description: File name content_type: type: - string - 'null' description: MIME type file_size: type: integer description: File size in bytes url: type: string description: Download URL (a private link with an expiring signature) EntryComment: type: object description: 'Entry comment. Each comment takes at most 3 attachments, each at most 5 MB; allowed extensions: jpg, jpeg, png, bmp, webp, heic, doc, docx, xls, xlsx, csv, ppt, pptx, pdf, txt, mp4, mov.' required: - id - created_at - updated_at properties: id: type: string description: Comment id content: type: string description: Comment text, with mentions in the form @[]; may be absent when the comment has only attachments creator: type: object description: Commenter; absent when the commenter's info is missing required: - id - name properties: id: type: string description: User id name: type: string description: User display name; when the account has been deleted, a placeholder such as `该账户已注销` parent_id: type: string description: id of the comment replied to; absent when not a reply created_at: type: string format: date-time description: Created at updated_at: type: string format: date-time description: Updated at mentions: type: array description: Mentioned cooperators; absent when there are no mentions items: $ref: '#/components/schemas/EntryCommentMention' attachments: type: array description: Attachments, by upload time ascending; absent when there are none items: $ref: '#/components/schemas/EntryCommentAttachment' EntryCommentInput: type: object properties: content: type: string maxLength: 2000 description: Comment text, cannot be empty once leading and trailing whitespace is trimmed; mention a cooperator with @[] (user_id is 24 hex characters) parent_id: type: string description: id of the parent comment being replied to; must belong to the same entry; read on create only additionalProperties: false OpensearchSearchFieldSetting: type: object required: - field_api_code properties: field_api_code: type: string description: api_code of the search field; must be a field the form allows searching on field_label: type: - string - 'null' description: Field label shown to the public; the field's own label is used when empty fuzzy: type: boolean default: false description: Whether to use fuzzy matching sms_verification: type: boolean default: false description: Whether SMS verification is required (applies to mobile fields only) OpensearchSearchFieldRule: type: object required: - search_field_settings properties: operand: type: string enum: - and - or default: and description: How the search fields within the rule are combined search_field_settings: type: array minItems: 1 description: Search field settings, cannot be empty items: $ref: '#/components/schemas/OpensearchSearchFieldSetting' OpensearchDisplayFieldRule: type: object required: - field_api_code properties: field_api_code: type: string description: api_code of the display field; must be a field the form allows displaying field_label: type: - string - 'null' description: Field label shown to the public; the field's own label is used when empty editable: type: boolean default: false description: Whether the searcher can edit this field on the results page protected: type: boolean default: false description: Whether privacy protection is on (masked display; applies only to fields that support privacy protection) highlight: type: - object - 'null' description: Highlight settings; null when not set properties: color: type: - string - 'null' description: Highlight color position: type: integer default: 999 description: Highlight sort position OpensearchQuerySummary: type: object required: - token - url - name - enabled - form_token - created_at - searches_count - views_count properties: token: type: string description: Public query token url: type: string description: Public URL of the public query (/os/{token}, on the account subdomain or a custom domain) name: type: string description: Name enabled: type: boolean description: Whether it is enabled form_token: type: - string - 'null' description: Token of the form it belongs to; null when the form has been deleted created_at: type: string format: date-time description: Created at searches_count: type: integer description: Total number of searches views_count: type: integer description: Total number of visits OpensearchQuery: allOf: - $ref: '#/components/schemas/OpensearchQuerySummary' - type: object required: - description - status - search_field_rules - display_field_rules - messages - default_messages - search_button - allow_to_export_results - header - updated_at properties: description: type: - string - 'null' description: Description text status: type: string enum: - active - entries_count_limited - form_not_found description: 'Status: active means usable; entries_count_limited means the form''s entry count exceeds the plan''s public query limit; form_not_found means the form has been deleted' search_field_rules: type: array description: Search field rules items: allOf: - $ref: '#/components/schemas/OpensearchSearchFieldRule' - type: object required: - operand display_field_rules: type: array description: Display field rules items: allOf: - $ref: '#/components/schemas/OpensearchDisplayFieldRule' - type: object required: - field_label - editable - protected - highlight messages: type: - object - 'null' description: Saved raw values of the prompt messages; an empty object or null when not customized properties: has_result: type: string description: Message shown when results are found no_result: type: string description: Message shown when no results are found default_messages: type: object description: Prompt messages with the product defaults merged in (in the form's language) required: - has_result - no_result properties: has_result: type: string description: Message shown when results are found no_result: type: string description: Message shown when no results are found search_button: type: object description: Search button settings; an empty object when not set properties: text: type: string description: Button text color: type: string description: Button color allow_to_export_results: type: boolean description: Whether the searcher may export results header: type: object description: Header settings required: - background_image properties: background_image: type: - object - 'null' description: Header background image; null when not set required: - attachment_id - position_x - position_y - image_url properties: attachment_id: type: string description: Background image attachment id position_x: type: - number - 'null' description: Horizontal position of the background image position_y: type: - number - 'null' description: Vertical position of the background image image_url: type: - string - 'null' description: Background image URL updated_at: type: string format: date-time description: Updated at OpensearchQueryInput: type: object description: Request body to create / update a public query; only the keys present are updated properties: form_token: type: string description: 'Used on create only: token of the form the query belongs to (can also be passed as a query parameter)' name: type: string description: Name, cannot be empty description: type: string description: Description text enabled: type: boolean description: Whether it is enabled search_field_rules: type: array minItems: 1 description: Search field rules, replaced as a whole; when given, cannot be an empty array, and each rule's search_field_settings cannot be empty items: $ref: '#/components/schemas/OpensearchSearchFieldRule' display_field_rules: type: array minItems: 1 description: Display field rules, replaced as a whole; when given, cannot be an empty array items: $ref: '#/components/schemas/OpensearchDisplayFieldRule' search_button: type: object description: Search button settings; only text and color are read properties: text: type: string description: Button text color: type: string description: Button color additionalProperties: false messages: type: object description: Prompt messages; only has_result and no_result are read; missing keys use the product defaults properties: has_result: type: string description: Message shown when results are found no_result: type: string description: Message shown when no results are found additionalProperties: false allow_to_export_results: type: boolean description: Whether the searcher may export results header: type: object description: Header settings; only attachment_id, image_upload_token, position_x and position_y of background_image are read (defined by the server implementation) properties: background_image: type: object properties: attachment_id: type: string description: Background image attachment id, returned by "Upload a form image" (`POST /form_image_attachments`, `image_type=opensearch_header`) image_upload_token: type: string description: 'Instead of attachment_id: after uploading with a `form_image_token` (purpose opensearch_header), pass that token directly. The token must be uploaded, unexpired, owned by the caller and have the purpose opensearch_header; otherwise returns 400' position_x: type: number description: Horizontal position of the background image position_y: type: number description: Vertical position of the background image additionalProperties: false additionalProperties: false extra_configurable_setting: type: object description: Extra settings (defined by the server implementation) properties: show_exam_correct_answer: type: boolean description: Whether to show the correct exam answers show_exam_explanation: type: boolean description: Whether to show the exam explanations additionalProperties: false scope_conditions: type: array description: Conditions that limit which entries can be searched; require plan support, otherwise returns 400; only trigger, operator, value, group_index and scope_attr are read from each item items: type: object properties: trigger: type: string description: api_code of the trigger field operator: type: string description: Operator (defined by the server implementation) value: description: Condition value group_index: type: integer description: Condition group index; conditions in the same group are combined with and, different groups with or scope_attr: type: string description: Attribute the condition applies to (defined by the server implementation) additionalProperties: false additionalProperties: false OpensearchQuerySuggestion: type: object required: - api_code - label - type - privacy_protectable - for_associated properties: api_code: type: string description: Field api_code label: type: string description: Field label type: type: string description: Field type name, e.g. TextField, MobileField privacy_protectable: type: boolean description: Whether privacy protection is supported for_associated: type: - boolean - 'null' description: Whether it is a field expanded from an associated form; null for non-associated fields OpensearchDisplayQuerySuggestion: allOf: - $ref: '#/components/schemas/OpensearchQuerySuggestion' - type: object required: - editable - scorable properties: editable: type: boolean description: Whether the field can be made editable by the person querying scorable: type: boolean description: Whether the field is scorable TextFieldInput: type: object title: TextFieldInput description: TextField field additionalProperties: false required: - type - label properties: type: const: TextField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has predefined_value: type: string description: Default value placeholder: type: string description: Placeholder text TextAreaInput: type: object title: TextAreaInput description: TextArea field additionalProperties: false required: - type - label properties: type: const: TextArea label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has predefined_value: type: string description: Default value placeholder: type: string description: Placeholder text NumberFieldInput: type: object title: NumberFieldInput description: NumberField field additionalProperties: false required: - type - label properties: type: const: NumberField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has predefined_value: type: - number - string description: Default value placeholder: type: string description: Placeholder text range_min: type: number description: Minimum value, inclusive range_max: type: number description: Maximum value, inclusive precision: type: integer minimum: 0 maximum: 14 description: Decimal places display_precision: type: integer minimum: 0 description: Decimal places shown display_as_percentage: type: boolean description: Show as a percentage; cannot be combined with thousands_separator thousands_separator: type: boolean description: Show a thousands separator; cannot be combined with display_as_percentage currency_symbol: type: string description: Currency symbol currency_symbol_position: type: string enum: - prefix - suffix description: Where the currency symbol goes icon_type: type: string enum: - none - number-2 - dollar1 - cny1 description: Field icon allOf: - description: display_as_percentage and thousands_separator cannot both be true not: properties: display_as_percentage: const: true thousands_separator: const: true required: - display_as_percentage - thousands_separator EmailFieldInput: type: object title: EmailFieldInput description: EmailField field additionalProperties: false required: - type - label properties: type: const: EmailField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has placeholder: type: string description: Placeholder text MobileFieldInput: type: object title: MobileFieldInput description: MobileField field additionalProperties: false required: - type - label properties: type: const: MobileField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has predefined_value: type: string description: Default value placeholder: type: string description: Placeholder text sms_verification: type: boolean description: Verify the number by SMS (this also turns on the image captcha) IdCardFieldInput: type: object title: IdCardFieldInput description: IdCardField field additionalProperties: false required: - type - label properties: type: const: IdCardField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has NameFieldInput: type: object title: NameFieldInput description: NameField field additionalProperties: false required: - type - label properties: type: const: NameField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has RadioButtonInput: type: object title: RadioButtonInput description: RadioButton field additionalProperties: false required: - type - label properties: type: const: RadioButton label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value CheckBoxInput: type: object title: CheckBoxInput description: CheckBox field additionalProperties: false required: - type - label properties: type: const: CheckBox label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens minimum_length: type: integer minimum: 0 description: Minimum number of choices; for a LikertField with likert_choice_style=multiple, the minimum per statement maximum_length: type: integer minimum: 0 description: Maximum number of choices; for a LikertField with likert_choice_style=multiple, the maximum per statement allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value DropDownInput: type: object title: DropDownInput description: DropDown field additionalProperties: false required: - type - label properties: type: const: DropDown label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value random_choices: type: boolean description: Shuffle the choices each time the form opens allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value DateTimeFieldInput: type: object title: DateTimeFieldInput description: DateTimeField field additionalProperties: false required: - type - label properties: type: const: DateTimeField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default predefined_value: type: string description: Default value precision: type: string enum: - month - day - minute - second description: Date precision; day by default RatingFieldInput: type: object title: RatingFieldInput description: RatingField field additionalProperties: false required: - type - label properties: type: const: RatingField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default rating_max: type: integer minimum: 1 description: Rating scale, such as 3 / 5 / 10; 5 by default TableFieldInput: type: object title: TableFieldInput description: TableField field additionalProperties: false required: - type - label properties: type: const: TableField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default dimensions: type: array minItems: 1 items: $ref: '#/components/schemas/DimensionInput' description: Sub-fields (columns) init_row_length: type: integer minimum: 1 description: Initial number of rows; 3 by default TelephoneFieldInput: type: object title: TelephoneFieldInput description: TelephoneField field additionalProperties: false required: - type - label properties: type: const: TelephoneField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has predefined_value: type: string description: Default value placeholder: type: string description: Placeholder text AddressFieldInput: type: object title: AddressFieldInput description: AddressField field additionalProperties: false required: - type - label properties: type: const: AddressField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default predefined_value: type: object description: Default address, keyed by province / city / district / street changeable: type: object description: 'Which levels of the AddressField can be changed: keys province / city / district / street, boolean values' additionalProperties: type: boolean enable_auto_position: type: boolean description: Fill in the address from the device location when the form first opens AttachmentFieldInput: type: object title: AttachmentFieldInput description: AttachmentField field additionalProperties: false required: - type - label properties: type: const: AttachmentField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default max_size: type: integer minimum: 1 maximum: 500 description: Maximum size of one file, in MB max_file_quantity: type: integer minimum: 1 description: Maximum number of files media_type: type: object additionalProperties: false description: 'Allowed file types: type is one preset group, whose extensions x-groups lists, or custom with the extensions listed in value. To allow several groups, write type=custom with the union of their extensions in value' x-groups: doc: - txt - pdf - doc - docx - xls - xlsx - ppt - pptx - wps - rtf - hlp image: - jpg - jpeg - png - gif - bmp - psd - tif - heic - heif video: - mkv - mp4 - avi - swf - wmv - rmvb - mov - mpg audio: - mp3 - flac - ape - wma - wav - aac - m4a - au - ram - mmf - aif compress: - rar - zip - 7z - gz - arj - z properties: type: type: string enum: - unlimited - doc - image - video - audio - compress - custom value: type: array items: type: string description: Lowercase extensions, without the dot if: properties: type: const: custom required: - type then: required: - value properties: value: minItems: 1 mobile_camera_only: type: boolean description: On mobile, only a photo taken with the camera; picking from the photo library is not allowed GeoFieldInput: type: object title: GeoFieldInput description: GeoField field additionalProperties: false required: - type - label properties: type: const: GeoField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default LinkFieldInput: type: object title: LinkFieldInput description: LinkField field additionalProperties: false required: - type - label properties: type: const: LinkField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has predefined_value: type: string description: Default value placeholder: type: string description: Placeholder text NpsFieldInput: type: object title: NpsFieldInput description: NpsField field additionalProperties: false required: - type - label properties: type: const: NpsField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default minimum_ratings_display_text: type: string description: Text shown at the lowest rating maximum_ratings_display_text: type: string description: Text shown at the highest rating TimeFieldInput: type: object title: TimeFieldInput description: TimeField field additionalProperties: false required: - type - label properties: type: const: TimeField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default predefined_value: type: object description: 'Default time, such as {"hour": 9, "minute": 30}' properties: hour: type: integer minute: type: integer second: type: integer include_second: type: boolean description: Include seconds SortFieldInput: type: object title: SortFieldInput description: SortField field additionalProperties: false required: - type - label properties: type: const: SortField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices random_choices: type: boolean description: Shuffle the choices each time the form opens ESignatureFieldInput: type: object title: ESignatureFieldInput description: ESignatureField field additionalProperties: false required: - type - label properties: type: const: ESignatureField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default AudioFieldInput: type: object title: AudioFieldInput description: AudioField field additionalProperties: false required: - type - label properties: type: const: AudioField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default max_duration: type: integer minimum: 1 maximum: 5 description: Maximum recording length, in minutes CascadeDropDownInput: type: object title: CascadeDropDownInput description: CascadeDropDown field additionalProperties: false required: - type - label properties: type: const: CascadeDropDown label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default choices: type: array minItems: 1 items: $ref: '#/components/schemas/CascadeChoiceInput' description: Choices levels: type: integer minimum: 2 description: Number of levels of the cascading drop-down; every choice path must reach this depth choice_filterable: type: boolean description: Allow filtering the choices random_choices: type: boolean description: Shuffle the choices each time the form opens calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value LikertFieldInput: type: object title: LikertFieldInput description: LikertField field additionalProperties: false required: - type - label properties: type: const: LikertField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices statements: type: array minItems: 1 items: $ref: '#/components/schemas/StatementInput' description: Statements horizontal_on_mobile: type: boolean description: Lay out horizontally on mobile likert_choice_style: type: string enum: - single - multiple description: One choice (single) or several (multiple) per statement minimum_length: type: integer minimum: 0 description: Minimum number of choices; for a LikertField with likert_choice_style=multiple, the minimum per statement maximum_length: type: integer minimum: 0 description: Maximum number of choices; for a LikertField with likert_choice_style=multiple, the maximum per statement calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value allOf: - description: minimum_length / maximum_length apply only when likert_choice_style=multiple if: not: properties: likert_choice_style: const: multiple required: - likert_choice_style then: not: anyOf: - required: - minimum_length - required: - maximum_length - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value MatrixFieldInput: type: object title: MatrixFieldInput description: MatrixField field additionalProperties: false required: - type - label properties: type: const: MatrixField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default dimensions: type: array minItems: 1 items: $ref: '#/components/schemas/DimensionInput' description: Sub-fields (columns) statements: type: array minItems: 1 items: $ref: '#/components/schemas/StatementInput' description: Statements horizontal_on_mobile: type: boolean description: Lay out horizontally on mobile advanced_feature: type: boolean description: Turn on the advanced features MatrixScaleFieldInput: type: object title: MatrixScaleFieldInput description: MatrixScaleField field additionalProperties: false required: - type - label properties: type: const: MatrixScaleField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default rating_max: type: integer minimum: 1 description: Rating scale, such as 3 / 5 / 10; 5 by default statements: type: array minItems: 1 items: $ref: '#/components/schemas/StatementInput' description: Statements horizontal_on_mobile: type: boolean description: Lay out horizontally on mobile GoodsFieldInput: type: object title: GoodsFieldInput description: GoodsField field additionalProperties: false required: - type - label properties: type: const: GoodsField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default goods_items: type: array minItems: 1 items: $ref: '#/components/schemas/GoodsItemInput' description: Goods items unit: type: string maxLength: 2 description: Unit of quantity, at most 2 characters collapse_on_mobile: type: boolean description: Collapse the goods list on mobile columns_on_mobile: type: integer minimum: 1 description: Goods per row on mobile FormulaFieldInput: type: object title: FormulaFieldInput description: FormulaField field additionalProperties: false required: - type - label properties: type: const: FormulaField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default formula_display: type: string description: The formula as HTML; refer to a field as or result_display_type: type: string enum: - string - numeric - datetime description: How the result is shown result_display_as_date: type: boolean description: Older spelling of result_display_type=datetime precision: type: integer minimum: 0 maximum: 14 description: Decimal places display_precision: type: integer minimum: 0 description: Decimal places shown display_as_percentage: type: boolean description: Show as a percentage; cannot be combined with thousands_separator thousands_separator: type: boolean description: Show a thousands separator; cannot be combined with display_as_percentage currency_symbol: type: string description: Currency symbol currency_symbol_position: type: string enum: - prefix - suffix description: Where the currency symbol goes icon_type: type: string enum: - none - formula-2 - date-2 - number-2 - dollar1 - cny1 - sum - text - text2 description: Field icon allOf: - description: display_as_percentage and thousands_separator cannot both be true not: properties: display_as_percentage: const: true thousands_separator: const: true required: - display_as_percentage - thousands_separator ReservationFieldInput: type: object title: ReservationFieldInput description: ReservationField field additionalProperties: false required: - type - label properties: type: const: ReservationField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default reservation_items: type: array minItems: 1 items: $ref: '#/components/schemas/ReservationItemInput' description: Reservation items allow_multiple_items: type: boolean description: One submission can book several items item_allow_multiple_reservations: type: boolean description: One item can be booked for several time slots allow_multiple_number: type: boolean description: Several places can be booked in one time slot use_daily_time_range: type: boolean description: Use a daily time slot table FormAssociationInput: type: object title: FormAssociationInput description: FormAssociation field additionalProperties: false required: - type - label - associated_form_token - associated_field_api_codes properties: type: const: FormAssociation label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has display_field_api_codes: type: array maxItems: 20 items: type: string description: api_code of the fields to display associated_form_token: type: string description: Token of the associated form associated_field_api_codes: type: array minItems: 1 maxItems: 4 items: type: string description: api_code of the association key fields privacy_safe: type: boolean description: Show the associated fields with privacy masking everywhere allow_reverse_association: type: boolean description: Show the reverse association on the associated form reverse_display_field_api_codes: type: array items: type: string description: api_code of the fields the reverse association shows ImageRadioButtonInput: type: object title: ImageRadioButtonInput description: ImageRadioButton field additionalProperties: false required: - type - label properties: type: const: ImageRadioButton label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default choices: type: array minItems: 1 items: $ref: '#/components/schemas/ImageChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value ImageCheckBoxInput: type: object title: ImageCheckBoxInput description: ImageCheckBox field additionalProperties: false required: - type - label properties: type: const: ImageCheckBox label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default choices: type: array minItems: 1 items: $ref: '#/components/schemas/ImageChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens minimum_length: type: integer minimum: 0 description: Minimum number of choices; for a LikertField with likert_choice_style=multiple, the minimum per statement maximum_length: type: integer minimum: 0 description: Maximum number of choices; for a LikertField with likert_choice_style=multiple, the maximum per statement allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value SectionBreakInput: type: object title: SectionBreakInput description: SectionBreak field additionalProperties: false required: - type - label properties: type: const: SectionBreak label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default show_split_line: type: boolean description: Show a divider line show_part_description: type: boolean description: Collapse the description when it is long PageBreakInput: type: object title: PageBreakInput description: PageBreak field additionalProperties: false required: - type - label properties: type: const: PageBreak label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default disable_previous_page: type: boolean description: Hide the "Previous" button previous_page_text: type: string description: Text of the "Previous" button next_page_text: type: string description: Text of the "Next" button count_down: type: integer minimum: 0 description: Seconds the "Next" button stays locked; 0 means not locked WidgetButtonInput: type: object title: WidgetButtonInput description: WidgetButton field additionalProperties: false required: - type - label properties: type: const: WidgetButton label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default buttons: type: array minItems: 1 items: $ref: '#/components/schemas/WidgetButtonItemInput' description: Buttons buttons_number: type: integer minimum: 1 description: Number of buttons; must equal the length of buttons fixed_to_bottom: type: boolean description: Pin the button bar to the bottom of the page WidgetContactInput: type: object title: WidgetContactInput description: WidgetContact field additionalProperties: false required: - type - label properties: type: const: WidgetContact label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default widget_images: type: array items: $ref: '#/components/schemas/WidgetImageInput' description: Images; each gives one of image_url / image_base64 / image_upload_token widget_max_images_number: type: integer minimum: 1 description: Maximum number of images shown; at least the length of widget_images phones: type: array description: Contact phone numbers items: type: object required: - phone additionalProperties: false properties: phone: type: string WidgetMapInput: type: object title: WidgetMapInput description: WidgetMap field additionalProperties: false required: - type - label properties: type: const: WidgetMap label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default nav_address: type: string description: Address text used for navigation longitude: type: number description: Longitude latitude: type: number description: Latitude value: type: string description: Value shown localizable_on_mobile: type: boolean description: On mobile, allow opening the location in a map WidgetMarqueeInput: type: object title: WidgetMarqueeInput description: WidgetMarquee field additionalProperties: false required: - type - label properties: type: const: WidgetMarquee label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default lines: type: integer minimum: 1 description: Number of scrolling lines entries_init_number: type: integer minimum: 0 description: Submission count to start from entries_number_visible: type: boolean description: Show the submission count marquee_data_type: type: string enum: - fake - real description: 'Data source: fake for generated data, real for real entries' SingleSelectInput: type: object title: SingleSelectInput description: SingleSelect question, stored as RadioButton; only when scene is exam / evaluation additionalProperties: false required: - type - label - choices - answers properties: type: const: SingleSelect label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 MultiSelectInput: type: object title: MultiSelectInput description: MultiSelect question, stored as CheckBox; only when scene is exam / evaluation additionalProperties: false required: - type - label - choices - answers properties: type: const: MultiSelect label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens minimum_length: type: integer minimum: 0 description: Minimum number of choices; for a LikertField with likert_choice_style=multiple, the minimum per statement maximum_length: type: integer minimum: 0 description: Maximum number of choices; for a LikertField with likert_choice_style=multiple, the maximum per statement answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - partial_absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 - description: In absolute mode, the answer value of a multiple-choice question is an array of choice labels if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: items: properties: value: type: array items: type: string minItems: 1 ImageSingleSelectInput: type: object title: ImageSingleSelectInput description: ImageSingleSelect question, stored as ImageRadioButton; only when scene is exam / evaluation additionalProperties: false required: - type - label - choices - answers properties: type: const: ImageSingleSelect label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default choices: type: array minItems: 1 items: $ref: '#/components/schemas/ImageChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 ImageMultiSelectInput: type: object title: ImageMultiSelectInput description: ImageMultiSelect question, stored as ImageCheckBox; only when scene is exam / evaluation additionalProperties: false required: - type - label - choices - answers properties: type: const: ImageMultiSelect label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default choices: type: array minItems: 1 items: $ref: '#/components/schemas/ImageChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens minimum_length: type: integer minimum: 0 description: Minimum number of choices; for a LikertField with likert_choice_style=multiple, the minimum per statement maximum_length: type: integer minimum: 0 description: Maximum number of choices; for a LikertField with likert_choice_style=multiple, the maximum per statement answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - partial_absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 - description: In absolute mode, the answer value of a multiple-choice question is an array of choice labels if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: items: properties: value: type: array items: type: string minItems: 1 TrueOrFalseInput: type: object title: TrueOrFalseInput description: TrueOrFalse question, stored as RadioButton; only when scene is exam additionalProperties: false required: - type - label - choices - answers properties: type: const: TrueOrFalse label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 DropDownSelectInput: type: object title: DropDownSelectInput description: DropDownSelect question, stored as DropDown; only when scene is exam / evaluation additionalProperties: false required: - type - label - choices - answers properties: type: const: DropDownSelect label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value random_choices: type: boolean description: Shuffle the choices each time the form opens answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 FillInBlankInput: type: object title: FillInBlankInput description: FillInBlank question, stored as TextField; only when scene is exam additionalProperties: false required: - type - label - answers properties: type: const: FillInBlank label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has predefined_value: type: string description: Default value placeholder: type: string description: Placeholder text answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 ShortAnswerInput: type: object title: ShortAnswerInput description: ShortAnswer question, stored as TextArea; only when scene is exam additionalProperties: false required: - type - label - answers properties: type: const: ShortAnswer label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has predefined_value: type: string description: Default value placeholder: type: string description: Placeholder text answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 FillInNumberInput: type: object title: FillInNumberInput description: FillInNumber question, stored as NumberField; only when scene is exam additionalProperties: false required: - type - label - answers properties: type: const: FillInNumber label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default unique: type: boolean description: Refuse a value an existing entry already has predefined_value: type: - number - string description: Default value placeholder: type: string description: Placeholder text range_min: type: number description: Minimum value, inclusive range_max: type: number description: Maximum value, inclusive precision: type: integer minimum: 0 maximum: 14 description: Decimal places display_precision: type: integer minimum: 0 description: Decimal places shown display_as_percentage: type: boolean description: Show as a percentage; cannot be combined with thousands_separator thousands_separator: type: boolean description: Show a thousands separator; cannot be combined with display_as_percentage currency_symbol: type: string description: Currency symbol currency_symbol_position: type: string enum: - prefix - suffix description: Where the currency symbol goes icon_type: type: string enum: - none - number-2 - dollar1 - cny1 description: Field icon answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: display_as_percentage and thousands_separator cannot both be true not: properties: display_as_percentage: const: true thousands_separator: const: true required: - display_as_percentage - thousands_separator - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 RatingInput: type: object title: RatingInput description: Rating question, stored as RatingField; only when scene is evaluation additionalProperties: false required: - type - label - answers properties: type: const: Rating label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default rating_max: type: integer minimum: 1 description: Rating scale, such as 3 / 5 / 10; 5 by default answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 NpsInput: type: object title: NpsInput description: Nps question, stored as NpsField; only when scene is evaluation additionalProperties: false required: - type - label - answers properties: type: const: Nps label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default minimum_ratings_display_text: type: string description: Text shown at the lowest rating maximum_ratings_display_text: type: string description: Text shown at the highest rating answers: type: array minItems: 1 items: $ref: '#/components/schemas/AnswerInput' description: Correct answers and their scores; for a choice question, value is the choice label answer_setting_mode: type: string enum: - absolute - relative description: Scoring mode; absolute by default (scores only when fully correct) answer_explanation: type: string description: Explanation of the answer allOf: - description: absolute mode takes a single answer if: anyOf: - not: required: - answer_setting_mode - properties: answer_setting_mode: const: absolute then: properties: answers: maxItems: 1 DepartmentInput: type: object title: DepartmentInput description: Department question, stored as RadioButton additionalProperties: false required: - type - label properties: type: const: Department label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value GradeInput: type: object title: GradeInput description: Grade question, stored as RadioButton additionalProperties: false required: - type - label properties: type: const: Grade label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default other_choice_required: type: boolean description: Choosing the "Other" choice requires the extra text choices: type: array minItems: 1 items: $ref: '#/components/schemas/ChoiceInput' description: Choices calculable: type: boolean description: Give each choice a numeric value; when on, every (leaf) choice must carry operand_value choices_layout: type: string description: How the choices are laid out random_choices: type: boolean description: Shuffle the choices each time the form opens allOf: - description: With calculable=true, every choice needs an operand_value if: properties: calculable: const: true required: - calculable then: properties: choices: items: required: - operand_value BooleanFieldInput: type: object title: BooleanFieldInput description: BooleanField field additionalProperties: false required: - type - label properties: type: const: BooleanField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default TableColumnInput: type: object description: A table column definition; type is limited to the column types a table supports required: - type - label properties: type: type: string enum: - TextArea - RadioButton - CheckBox - BooleanField - MobileField - NumberField - DateTimeField - EmailField - LinkField - AttachmentField - FormulaField - RelationField label: type: string description: Field label discriminator: propertyName: type mapping: TextArea: "#/components/schemas/TextAreaInput" RadioButton: "#/components/schemas/RadioButtonInput" CheckBox: "#/components/schemas/CheckBoxInput" BooleanField: "#/components/schemas/BooleanFieldInput" MobileField: "#/components/schemas/MobileFieldInput" NumberField: "#/components/schemas/NumberFieldInput" DateTimeField: "#/components/schemas/DateTimeFieldInput" EmailField: "#/components/schemas/EmailFieldInput" LinkField: "#/components/schemas/LinkFieldInput" AttachmentField: "#/components/schemas/AttachmentFieldInput" FormulaField: "#/components/schemas/FormulaFieldInput" RelationField: "#/components/schemas/RelationFieldInput" oneOf: - $ref: '#/components/schemas/TextAreaInput' - $ref: '#/components/schemas/RadioButtonInput' - $ref: '#/components/schemas/CheckBoxInput' - $ref: '#/components/schemas/BooleanFieldInput' - $ref: '#/components/schemas/MobileFieldInput' - $ref: '#/components/schemas/NumberFieldInput' - $ref: '#/components/schemas/DateTimeFieldInput' - $ref: '#/components/schemas/EmailFieldInput' - $ref: '#/components/schemas/LinkFieldInput' - $ref: '#/components/schemas/AttachmentFieldInput' - $ref: '#/components/schemas/FormulaFieldInput' - $ref: '#/components/schemas/RelationFieldInput' title: TableColumnInput ImageChoiceInput: type: object title: ImageChoiceInput additionalProperties: false description: An image choice; value is its text label, and one of image_url / image_base64 / image_upload_token is required allOf: - anyOf: - required: - value - required: - name - anyOf: - required: - image_url - required: - image_base64 - required: - image_upload_token properties: value: type: string description: Choice label name: type: string description: Same as value api_code: type: string description: The choice api_code; generated by the server when left out, and keeps the identity of the choice on edit operand_value: type: number description: Numeric value of the choice selected: type: boolean description: Selected by default image_url: type: string format: uri description: Publicly reachable image URL image_base64: type: string description: The image as Base64; only for very small images image_upload_token: type: string description: The `form_image_token` used by "Upload a form image"; the image purpose must be field_choice CascadeChoiceInput: type: object title: CascadeChoiceInput additionalProperties: false description: A cascading drop-down choice; sub_choices holds the next level, and every path must be exactly levels deep anyOf: - required: - value - required: - name properties: value: type: string description: Choice label name: type: string description: Same as value api_code: type: string description: The choice api_code; generated by the server when left out, and keeps the identity of the choice on edit quota: type: integer minimum: 1 description: Maximum number of places; leave out for no limit operand_value: type: number description: Numeric value of the choice selected: type: boolean description: Selected by default sub_choices: type: array items: $ref: '#/components/schemas/CascadeChoiceInput' description: Choices of the next level AnswerInput: type: object title: AnswerInput additionalProperties: false required: - value - score properties: value: description: 'The correct answer: the choice label for a choice question (an array for multiple choice in absolute mode), the expected text for fill-in-the-blank, the expected number for a number question' score: type: number description: Score ReservationByDayQuotaInput: type: object title: ReservationByDayQuotaInput additionalProperties: false required: - type properties: type: const: by_day_repeat_weekly available_days_of_week: type: array items: type: string enum: - sunday - monday - tuesday - wednesday - thursday - friday - saturday description: Days of the week that can be booked, as lowercase English day names show_left_quota: type: boolean description: Show the places left start_time_offset: type: object additionalProperties: false properties: offset_number: type: integer minimum: 0 unit: type: string enum: - day - hour description: How far in advance booking opens end_time_offset: type: object additionalProperties: false properties: offset_number: type: integer minimum: 0 unit: type: string enum: - day - hour description: How far in advance booking closes daily_time_range_quotas: type: array items: type: object additionalProperties: false properties: for_wday: type: string enum: - sunday - monday - tuesday - wednesday - thursday - friday - saturday description: Day of the week, as a lowercase English day name quota: type: integer minimum: 0 description: Places price: type: number minimum: 0 description: Price when payable position: type: integer minimum: 0 daily_time_range_token: type: string description: Places per day of the week non_reservable_rules: type: array items: type: object additionalProperties: false properties: start_time: type: string end_time: type: string description: Time ranges that cannot be booked ReservationByTimeRangeQuotaInput: type: object title: ReservationByTimeRangeQuotaInput additionalProperties: false required: - type properties: type: const: by_time_range_repeat_daily available_days_of_week: type: array items: type: string enum: - sunday - monday - tuesday - wednesday - thursday - friday - saturday description: Days of the week that can be booked, as lowercase English day names show_left_quota: type: boolean description: Show the places left start_time_offset: type: object additionalProperties: false properties: offset_number: type: integer minimum: 0 unit: type: string enum: - day - hour description: How far in advance booking opens end_time_offset: type: object additionalProperties: false properties: offset_number: type: integer minimum: 0 unit: type: string enum: - day - hour description: How far in advance booking closes daily_time_range_quotas: type: array items: type: object additionalProperties: false required: - start_time - end_time properties: for_wday: type: string enum: - sunday - monday - tuesday - wednesday - thursday - friday - saturday description: Day of the week, as a lowercase English day name quota: type: integer minimum: 0 description: Places price: type: number minimum: 0 description: Price when payable position: type: integer minimum: 0 daily_time_range_token: type: string start_time: type: object additionalProperties: false properties: hour: type: integer minimum: 0 maximum: 23 minute: type: integer minimum: 0 maximum: 59 description: Start time end_time: type: object additionalProperties: false properties: hour: type: integer minimum: 0 maximum: 23 minute: type: integer minimum: 0 maximum: 59 description: End time description: Places per time slot non_reservable_rules: type: array items: type: object additionalProperties: false properties: start_time: type: string end_time: type: string description: Time ranges that cannot be booked time_range_mode: type: string enum: - same_by_wday - different_by_wday description: 'same_by_wday: the same time slots every day; different_by_wday: every slot must carry for_wday' if: properties: time_range_mode: const: different_by_wday required: - time_range_mode then: properties: daily_time_range_quotas: items: required: - for_wday WidgetImageInput: type: object title: WidgetImageInput additionalProperties: false anyOf: - required: - image_url - required: - image_base64 - required: - image_upload_token properties: image_url: type: string format: uri image_base64: type: string image_upload_token: type: string FormCreateConstraints: title: FormCreateConstraints description: Constraints between fields and scene / layout when creating a form allOf: - description: The card layout cannot hold field types the paged layout cannot render if: properties: layout: const: card required: - layout then: properties: fields: items: properties: type: not: enum: - PageBreak - MultipleBlanksField - WidgetContact - WidgetVideo - WidgetButton - description: SingleSelect / MultiSelect / ImageSingleSelect / ImageMultiSelect / DropDownSelect can only be used when scene is exam / evaluation if: properties: fields: type: array contains: properties: type: enum: - SingleSelect - MultiSelect - ImageSingleSelect - ImageMultiSelect - DropDownSelect required: - type required: - fields then: properties: scene: enum: - exam - evaluation required: - scene - description: TrueOrFalse / FillInBlank / ShortAnswer / FillInNumber can only be used when scene is exam if: properties: fields: type: array contains: properties: type: enum: - TrueOrFalse - FillInBlank - ShortAnswer - FillInNumber required: - type required: - fields then: properties: scene: enum: - exam required: - scene - description: Rating / Nps can only be used when scene is evaluation if: properties: fields: type: array contains: properties: type: enum: - Rating - Nps required: - type required: - fields then: properties: scene: enum: - evaluation required: - scene WidgetButtonItemInput: type: object title: WidgetButtonItemInput additionalProperties: false required: - text properties: text: type: string description: Button text position: type: integer minimum: 0 link_type: type: string enum: - normal - miniapp - phone - qrcode description: Link type; normal by default link_attrs: type: object description: 'Link attributes, such as {"url": "https://..."}' url: type: string format: uri description: Link URL, used when link_attrs is left out FieldDataCheckResponse: type: object required: - form_token - results properties: form_token: type: string description: Form (or table) token results: type: array description: Check results, one per item of `checks` in the request, in the same order items: oneOf: - $ref: '#/components/schemas/FieldDataCheckResult' - $ref: '#/components/schemas/FieldCheckUnavailable' FieldDataCheckResult: type: object required: - field_api_code - field_label - has_data properties: field_api_code: type: string description: Field api_code field_label: type: string description: Field label has_data: type: boolean description: Whether the field (or that choice, when `choice_value` was passed) already has submitted entries choice_value: type: string description: The `choice_value` passed in the request; omitted when not passed FieldCheckUnavailable: type: object description: An item that cannot be checked / previewed required: - field_api_code - unavailable properties: field_api_code: type: - string - 'null' description: The `field_api_code` passed in the request unavailable: type: string description: Why it cannot be checked examples: - 'Field not found: field_9. Read the form''s fields to see the current ones.' FieldTypeChangePreviewResponse: type: object required: - form_token - results properties: form_token: type: string description: Form (or table) token results: type: array description: Preview results, one per item of `checks` in the request, in the same order items: oneOf: - $ref: '#/components/schemas/FieldTypeChangePreviewResult' - $ref: '#/components/schemas/FieldCheckUnavailable' FieldTypeChangePreviewResult: type: object required: - field_api_code - field_label - source_type - target_type - supported properties: field_api_code: type: string description: Field api_code field_label: type: string description: Field label source_type: type: string description: The field's current type examples: - TextField target_type: type: string description: Target type examples: - RadioButton supported: type: boolean description: Whether the conversion is supported. When `false`, the counts below are not returned and the actual edit is rejected too retained_count: type: integer description: Number of entries that keep their value after the conversion (returned when `supported=true`) cleared_count: type: integer description: Number of entries whose value is cleared by the conversion (returned when `supported=true`); 0 means the conversion is lossless choice_count: type: integer description: For a multi-line text to choice field conversion, the number of choices that will be generated from existing entries; not returned for other conversions choice_limit_exceeded: type: boolean description: For a multi-line text to choice field conversion, whether the number of generated choices exceeds the limit (the conversion is rejected when it does); not returned for other conversions FieldTypeListResponse: type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/FieldTypeDescription' FieldTypeDescription: type: object required: - type - takes_choices - flags - settings properties: type: type: string description: Field type name, i.e. a value of `fields[].type` examples: - RadioButton base_type: type: string description: The base field type this type builds on (e.g. the exam question type `SingleSelect` builds on `RadioButton` and has the same capabilities); omitted when it equals `type` examples: - RadioButton scorable: type: boolean const: true description: "`true` for scored exam question types; omitted for other types" takes_choices: type: boolean description: Whether it takes `choices` flags: type: array description: Supported validation flags, i.e. the boolean keys usable in `fields[]` items: type: string enum: - required - unique - other_choice_required settings: type: array description: Setting keys specific to this type (set on `fields[]`) items: type: string examples: - - calculable - choices_layout setting_specs: type: object description: What each key of `settings` may hold, keyed by setting, as the JSON Schema the create request validates it against (the setting's schema in `Input`). An attachment's `media_type` also carries `x-groups`, the extensions of each preset group. Omitted when the type has no settings additionalProperties: type: object examples: - media_type: type: object x-groups: audio: - mp3 - wav properties: type: type: string enum: - unlimited - audio - custom value: type: array items: type: string summary: type: string description: A short explanation of what this field is and how to write it. Omitted when `kind=table` field_example: type: object description: A complete example to put in `fields[]`. Returned only by `GET /field_types/{type}`; omitted when `kind=table` note: type: string description: What the example cannot show and is easy to get wrong. Returned only by `GET /field_types/{type}`; omitted when there is none EntryCountResponse: type: object required: - matched_entries properties: matched_entries: type: integer description: Number of entries matching the conditions examples: - matched_entries: 1284 EntryAggregateColumn: type: object description: Describes a result column. Group columns come first (`kind` is `dimension`), metric columns after (`kind` is `metric`), in the order of the request. required: - kind - field - label properties: kind: type: string enum: - dimension - metric field: type: string description: Field api_code label: type: string description: Field label func: type: string description: Aggregate function (metric columns only) bucket: type: string enum: - day - week - month description: Date bucket granularity (columns grouped by date only) EntryAggregateResponse: type: object required: - columns - rows - matched_entries - row_count - truncated - tz properties: columns: type: array items: $ref: '#/components/schemas/EntryAggregateColumn' rows: type: array description: | Each row's values match `columns` one to one. - Group columns: `{"api_code", "label"}` for choice fields, a string otherwise (for a date group, the identifier of that period); entries with that field empty form a group of their own, with the value `null`. - Metric columns: numbers; `min` / `max` of a date field are ISO 8601 times in Beijing time (UTC+8); `null` when there is no value. items: type: array items: type: - number - string - object - 'null' properties: api_code: type: string label: type: string matched_entries: type: integer description: Number of entries counted (entries matching the filters, not the number of groups) row_count: type: integer description: Total number of groups (1 when not grouped); may exceed the number of `rows` truncated: type: boolean description: The number of groups exceeds `limit`; `rows` holds only some of the groups tz: type: string description: Time zone used for date groups and time values examples: - Asia/Shanghai examples: - columns: - kind: dimension field: field_3 label: 城市 - kind: metric func: sum field: field_5 label: 金额 rows: - - api_code: bj label: 北京 - 1520.5 - - - 300 matched_entries: 42 row_count: 2 truncated: false tz: Asia/Shanghai EntrySummaryBucket: type: object required: - api_code - label - count - ratio properties: api_code: type: - string - 'null' description: Choice api_code; null for fields grouped by value that have no matching choice (such as address, goods, NPS) label: type: string description: Choice label or group value count: type: integer ratio: type: number description: Share of the entries that answered the field (0 to 1, 4 decimal places) EntrySummaryField: type: object description: | Profile of one field. Every field has `api_code` / `label` / `kind` / `answered` / `null_count`; the other properties depend on `kind`: | kind | Properties | |---|---| | `choice` | `buckets` | | `matrix` | `series` | | `number` | `stats` | | `date` | `earliest` / `latest` | | `text` | `count_unique` | | `geo` | none | required: - api_code - label - kind - answered - null_count properties: api_code: type: string label: type: string kind: type: string enum: - choice - matrix - number - date - text - geo answered: type: integer description: Number of entries that filled in this field null_count: type: integer description: Number of entries that left this field empty buckets: type: array items: $ref: '#/components/schemas/EntrySummaryBucket' series: type: array description: Distribution per question, for matrix fields items: type: object required: - api_code - label - answered - buckets properties: api_code: type: string description: Statement api_code label: type: string answered: type: integer buckets: type: array items: $ref: '#/components/schemas/EntrySummaryBucket' stats: type: object description: Numeric statistics; an empty object when there are no entries properties: min: type: number max: type: number sum: type: number avg: type: number earliest: type: - string - 'null' format: date-time description: Earliest date value (ISO 8601, Beijing time, UTC+8) latest: type: - string - 'null' format: date-time description: Latest date value (ISO 8601, Beijing time, UTC+8) count_unique: type: - integer - 'null' description: Number of distinct values EntrySummaryResponse: type: object required: - fields - truncated - omitted_fields - tz properties: overview: type: object description: Overview; omitted when `include_overview=false` required: - matched_entries - today_entries properties: matched_entries: type: integer description: Number of entries matching the filters today_entries: type: integer description: How many of them were created today (Beijing time, UTC+8) fields: type: array items: $ref: '#/components/schemas/EntrySummaryField' truncated: type: boolean description: More than 60 analysable fields; some fields are not returned omitted_fields: type: array description: api_codes of the fields left out by the 60-field cap items: type: string tz: type: string description: Time zone used for date values and for "today" examples: - Asia/Shanghai examples: - overview: matched_entries: 42 today_entries: 3 fields: - api_code: field_3 label: 城市 kind: choice answered: 40 null_count: 2 buckets: - api_code: bj label: 北京 count: 25 ratio: 0.625 - api_code: sh label: 上海 count: 15 ratio: 0.375 - api_code: field_5 label: 金额 kind: number answered: 42 null_count: 0 stats: min: 10 max: 200 sum: 1820.5 avg: 43.35 truncated: false omitted_fields: [] tz: Asia/Shanghai EntryFormUnavailable: type: object description: A form that could not be counted / searched required: - form_token - unavailable properties: form_token: type: string description: The token from the request, or the form token unavailable: type: string description: Why it could not be counted / searched EntryCountBatchResponse: type: object required: - matched_entries - forms properties: matched_entries: type: integer description: Sum of the counts of the forms that could be counted forms: type: array description: One item per token, in the request's order (after deduplication) items: oneOf: - type: object required: - form_token - name - matched_entries properties: form_token: type: string name: type: string matched_entries: type: integer - $ref: '#/components/schemas/EntryFormUnavailable' examples: - matched_entries: 130 forms: - form_token: abc123 name: 报名表 matched_entries: 130 - form_token: zzz999 unavailable: Form not found or access denied — check the token, and note it may belong to a different account than the one this credential belongs to. EntrySearchResponse: type: object required: - total - forms properties: total: type: integer description: Total matches across the forms forms: type: array description: Forms with matches, and forms that could not be searched; forms without matches are not listed items: oneOf: - type: object required: - form_token - name - matched - serial_numbers properties: form_token: type: string name: type: string matched: type: integer description: Number of matching entries serial_numbers: type: array description: Serial numbers of some matching entries, at most 50 items: type: integer - $ref: '#/components/schemas/EntryFormUnavailable' examples: - total: 3 forms: - form_token: abc123 name: 报名表 matched: 3 serial_numbers: - 12 - 57 - 88 EntryStatsResponse: type: object required: - from - to - tz - total - forms_with_data - count - data - truncated properties: from: type: string format: date to: type: string format: date tz: type: string examples: - Asia/Shanghai total: type: integer description: Total submissions across all forms in the range forms_with_data: type: integer description: Number of forms with submissions in the range count: type: integer description: Number of rows in `data` data: type: array description: Forms with submissions, most submissions first items: $ref: '#/components/schemas/EntryStatsFormRow' truncated: type: boolean description: More forms have submissions than `limit`; `data` holds only the first `limit` buckets: type: array description: Present only when `by` is passed; one item per period in the range, oldest first items: $ref: '#/components/schemas/EntryStatsBucket' examples: - from: '2026-09-01' to: '2026-09-07' tz: Asia/Shanghai total: 210 forms_with_data: 2 count: 2 data: - token: abc123 name: 报名表 kind: form fill_count: 180 - token: def456 name: 客户台账 kind: table fill_count: 30 truncated: false EntryStatsFormRow: type: object required: - token - name - kind - fill_count properties: token: type: string name: type: string kind: type: string enum: - form - table fill_count: type: integer description: Submissions in the period EntryStatsBucket: type: object description: Submission counts for one period, shaped like the overall statistics required: - from - to - total - forms_with_data - count - data - truncated properties: from: type: string format: date description: First day of the period, inclusive; the first period is clipped to the range to: type: string format: date description: Last day of the period, inclusive; the last period is clipped to the range total: type: integer forms_with_data: type: integer count: type: integer data: type: array description: Forms with submissions in this period, most submissions first, at most `limit` rows items: $ref: '#/components/schemas/EntryStatsFormRow' truncated: type: boolean FieldAnalytics: type: object description: Statistics the field supports; present on analysable fields only when `include_analytics=true` required: - agg_funcs - summary_kind - groupable - buckets - default_agg - summarisable properties: agg_funcs: type: array description: Functions the aggregate endpoint's `metrics` can apply to this field items: type: string summary_kind: type: string description: This field's `kind` in the data summary enum: - choice - matrix - number - date - text - geo groupable: type: boolean description: Whether it can be used in the aggregate endpoint's `dimensions` buckets: type: array description: The `bucket` values usable when grouping by this field (non-empty for date fields only) items: type: string enum: - day - week - month default_agg: type: string description: Suggested default aggregate function (`sum` for numbers, `count` otherwise) summarisable: type: boolean description: Whether the data summary includes this field MyFilledForm: type: object required: - token - name - description - kind - scene - submitted_entries_count - last_submitted_at properties: token: type: string description: Form token name: type: string description: Form name (the public name) description: type: - string - 'null' description: Form description (may be HTML rich text) kind: type: string description: Form kind, `form` or `table` examples: - form scene: type: - string - 'null' description: Form scene submitted_entries_count: type: integer description: Number of entries the current user submitted to this form last_submitted_at: type: - string - 'null' format: date-time description: When the current user last submitted (UTC) MyFilledFormListResponse: type: object required: - total - count - data - next properties: total: type: integer description: Total number of forms filled in count: type: integer description: Number of items on this page data: type: array items: $ref: '#/components/schemas/MyFilledForm' next: type: - integer - 'null' description: Row offset of the next page; null on the last page MySubmittedEntryListResponse: type: object required: - total - count - data - next properties: total: type: integer description: Total number of the current user's own entries matching the conditions count: type: integer description: Number of items on this page data: type: array description: Entries the current user submitted, with only the fields the form shows to submitters; see `EntryData` for value shapes items: $ref: '#/components/schemas/EntryData' next: type: - integer - 'null' description: Row offset of the next page; null on the last page FillPage: type: object required: - kind - token - title - fill_url - status - blockers - fields properties: kind: type: string enum: - form - form_view description: "`form` for a `/f/` link, `form_view` for a `/v/` link (a form view of a table)" token: type: string description: The token in the link title: type: string description: Fill page title; the view title for a form view description: type: - string - 'null' fill_url: type: string description: Fill page URL status: type: object required: - key properties: key: type: string description: "`open` means the current user can submit" message: type: - string - 'null' description: Message to show the user when they cannot submit open_info: type: array description: Opening times, when the page is not open yet or closed by schedule items: type: string blockers: type: array description: Requirements only the submitter can complete on the page; when not empty, the page can only be filled in a browser items: type: object required: - key - message properties: key: type: string enum: - captcha - sms_verification - weixin - ip_or_device_limit - region_limit - payment - portal - exam - required_attachment message: type: string fields: type: array description: Fields on the fill page, in fill order items: $ref: '#/components/schemas/FieldMap' manageable: type: object description: Returned only when the current user can already read the form or table behind the page properties: kind: type: string enum: - form - table token: type: string name: type: string FillEntryRequest: type: object required: - entry properties: entry: type: object description: Map of field api_code to value, values written as when creating entries; fields not visible on the fill page are ignored password: type: string description: The password the submitter provides when the fill page has an access password FillEntryCreated: type: object required: - serial_number properties: serial_number: type: integer description: Entry serial number entry_token: type: string created_at: type: string format: date-time MySearchFormResult: type: object required: - form_token properties: form_token: type: string description: Form token name: type: - string - 'null' description: Form name; omitted when `unavailable` matched: type: integer description: Number of the current user's own entries in this form that match; omitted when `unavailable` serial_numbers: type: array maxItems: 50 description: Serial numbers of matching entries, at most 50; omitted when `unavailable` items: type: integer unavailable: type: string description: Why this form cannot be searched; when present, `name` / `matched` / `serial_numbers` are absent MySearchResponse: type: object required: - total - forms properties: total: type: integer description: Total matches across all forms forms: type: array description: Forms with matches or that cannot be searched; forms without matches are left out items: $ref: '#/components/schemas/MySearchFormResult' TableFolderMoveResult: type: object required: - table_token - folder_token properties: table_token: type: string folder_token: type: - string - 'null' description: Token of the folder it is in after the move; null when moved out of folders FormTransactions: type: object description: | Payment statistics, grouped by transaction status (present when `include_transactions=true` and the form is bound to a payment account). Only the `paid` group exists for now: entries whose transaction status is paid or refunding, summed by order total (refunds not deducted); refunded and partially refunded entries are not counted. This is not a net income report. An amount of 0 does not mean the form is not a payment form. required: - paid properties: paid: type: object required: - amount - count properties: amount: type: number description: Sum of the order totals of this group's entries, in yuan (CNY) count: type: integer description: Number of entries in this group FormDetail: description: Form structure, plus what the `include_*` parameters add allOf: - $ref: '#/components/schemas/Form' - type: object properties: theme: type: object description: Form theme (present when `include_theme=true`); same shape as `FormTheme`, but without `form_token`. An empty object when the form has no theme additionalProperties: true field_rules: type: array description: Field display rules (present when `include_field_rules=true`), same as `data` of `GET /forms/{form_token}/field_rules` items: $ref: '#/components/schemas/FieldRule' extended_attributes: type: array description: Source-tracking links (present when `include_extended_attributes=true`), same as `data` of `GET /forms/{form_token}/extended_attributes` items: $ref: '#/components/schemas/ExtendedAttribute' transactions: $ref: '#/components/schemas/FormTransactions' FormViewFillItem: type: object description: One fill item on a form view's fill page (effective values) required: - api_code - label - notes - required properties: api_code: type: string description: The column's api_code label: type: - string - 'null' description: Label shown on the fill page (the column label unless set separately) notes: type: - string - 'null' description: Notes shown on the fill page (the column notes unless set separately) required: type: boolean description: Whether it is required FormViewFieldOverrideInput: type: object description: Configuration of one fill item of a form view required: - field_api_code properties: field_api_code: type: string description: The column's api_code; the column must exist and be usable as a fill item, and cannot repeat within one request label: type: - string - 'null' description: Label on the fill page; falls back to the column label when empty notes: type: - string - 'null' description: Notes on the fill page; falls back to the column notes when empty private: type: - boolean - 'null' description: When true, hidden from the fill page; when not passed, follows the column's own setting position: type: - integer - 'null' description: Position on the fill page; when not passed, the array order validations: type: array description: Validations of this fill item; currently `presence` marks it required. Each must be a validation the column type supports (e.g. yes/no and formula columns cannot be made required); otherwise returns 422 items: type: string examples: - presence additionalProperties: false EntryImportInput: type: object description: Request body of POST /forms/{form_token}/entry_imports required: - attachment_id - columns properties: attachment_id: type: string description: The import attachment `id` returned by "Upload an import file" columns: type: array minItems: 1 description: Column mapping; each item writes one spreadsheet column into one field items: $ref: '#/components/schemas/EntryImportColumnInput' header_row_index: type: - integer - string - 'null' pattern: "^[0-9]+$" description: Row number of the header row (as numbered in the spreadsheet, starting at 1); defaults to the first row of the spreadsheet, and data rows must follow below it examples: - 1 unique_field_code: type: - string - 'null' description: api_code of the dedup field; a row is skipped when the file's value for this field already exists in the form's entries additionalProperties: false EntryImportColumnInput: type: object required: - field_api_code properties: field_api_code: type: string description: api_code of the target field; must be a field of this form that accepts imports column_label: type: string description: Header text of the source column, matched exactly after trimming leading and trailing spaces; give at least one of this and `sheet_column_index` sheet_column_index: type: - integer - string pattern: "^[0-9]+$" description: Column number of the source column (as numbered in the spreadsheet, starting at 1); for a missing or duplicate header. Takes precedence over `column_label` additionalProperties: false examples: - field_api_code: field_1 column_label: 姓名 - field_api_code: field_2 sheet_column_index: 3 EntryImportCreated: type: object required: - job_id - status properties: job_id: type: string description: Import job ID, for "Show an entry import job" status: type: string description: Job status; `pending` right after creation enum: - pending - running - success - failed - cancelled EntryImportJob: type: object required: - job_id - status - total_rows - processed_rows - imported_count - skip_count - invalid_count - warnings - error_message - started_at - finished_at properties: job_id: type: string status: type: string description: "`pending` queued, `running` in progress; `success` / `failed` / `cancelled` are final" enum: - pending - running - success - failed - cancelled total_rows: type: - integer - 'null' description: Number of data rows to import; null before the job starts processed_rows: type: integer description: Rows processed imported_count: type: - integer - 'null' description: Rows written successfully; may be null before the job finishes skip_count: type: - integer - 'null' description: Rows skipped (e.g. deduplicated by `unique_field_code`) invalid_count: type: - integer - 'null' description: Rows that failed field validation warnings: type: array description: Per-row messages items: type: string error_message: type: - string - 'null' description: Why the job failed started_at: type: - string - 'null' format: date-time description: When the job started (UTC) finished_at: type: - string - 'null' format: date-time description: When the job finished (UTC) TimeOfDay: type: object required: - hour - minute properties: hour: type: integer minimum: 0 maximum: 23 minute: type: integer minimum: 0 maximum: 59 additionalProperties: false DailyRepeatCloseRuleInput: type: - object - 'null' description: | Daily open hours: the form accepts submissions only within these periods each day (e.g. 11:00-12:40, 17:00-18:30). It can coexist with `by_time_range_close_rule` and `by_entries_close_rule`. Passing `time_periods` replaces all existing periods; passing `{ "enabled": false }` deletes the rule. The `end_time` of each period must not be earlier than its `start_time`; otherwise returns 400. properties: enabled: type: boolean description: Pass false to delete the rule; omit it when passing `time_periods` time_periods: type: array description: One daily open period per item items: type: object required: - start_time - end_time properties: start_time: $ref: '#/components/schemas/TimeOfDay' end_time: $ref: '#/components/schemas/TimeOfDay' additionalProperties: false additionalProperties: false examples: - time_periods: - start_time: hour: 11 minute: 0 end_time: hour: 12 minute: 40 - enabled: false DailyRepeatCloseRule: type: - object - 'null' description: Daily open hours; null when not set required: - time_periods properties: time_periods: type: array items: type: object required: - start_time - end_time properties: start_time: type: object properties: hour: type: integer minute: type: integer end_time: type: object properties: hour: type: integer minute: type: integer TradePageInfo: type: object required: - total - page - per_page - total_pages properties: total: type: integer description: Total matching records (not just this page) page: type: integer description: Current page number (starting at 1) per_page: type: integer description: Records per page total_pages: type: integer description: Total pages TradeQueriedRange: type: object description: The date range actually used (Beijing time, UTC+8, both end days inclusive). Both ends are null when the query has no time limit. required: - start_date - end_date properties: start_date: type: - string - 'null' format: date end_date: type: - string - 'null' format: date TradeTransaction: type: object required: - trade_no - merchant_out_trade_no - out_trade_no - amount - paid_status - paid_status_label - transaction_fee - payment_channel - form_name - form_token - ordered_at - paid_at properties: trade_no: type: - string - 'null' description: Transaction number merchant_out_trade_no: type: - string - 'null' description: Merchant order number out_trade_no: type: - string - 'null' description: Jinshuju order number amount: type: number description: Order amount, in yuan (CNY) paid_status: type: string enum: - paid - unpaid - refunded - refunding - partial_refunded description: Payment status paid_status_label: type: - string - 'null' description: Chinese name of the payment status (`已支付` / `未支付` / `已退款` / `退款中` / `部分退款`) transaction_fee: type: - number - 'null' description: Transaction fee, in yuan (CNY) payment_channel: type: - string - 'null' enum: - wxpay - alipay - description: Payment channel; null when no payment has been started form_name: type: - string - 'null' description: Payment form name form_token: type: - string - 'null' description: Payment form token; null when the form no longer exists ordered_at: type: - string - 'null' format: date-time description: When the order was placed paid_at: type: - string - 'null' format: date-time description: When it was paid; null when unpaid TradeTransactionMetrics: type: object required: - transactions_amount - transactions_count - orders_count properties: transactions_amount: type: number description: 'Transaction amount, in yuan (CNY): the amount of paid-type orders minus their own successful refunds' transactions_count: type: integer description: 'Paid count: number of orders that are paid, partially refunded or refunding' orders_count: type: integer description: 'Order count: number of all matching orders, unpaid included' TradeTransactionListResponse: type: object required: - page_info - queried_range - transactions properties: page_info: $ref: '#/components/schemas/TradePageInfo' queried_range: $ref: '#/components/schemas/TradeQueriedRange' transactions: type: - array - 'null' description: Orders on this page, latest order time first; null when the detail limit is exceeded items: $ref: '#/components/schemas/TradeTransaction' next: type: string description: Number of the next page; pass it back unchanged as the `next` parameter. Omitted when there is no next page detail_limit: type: string description: Why the detail limit was exceeded; omitted when it was not stats: $ref: '#/components/schemas/TradeTransactionMetrics' description: Statistics for the range, given when the detail limit is exceeded; omitted when it is not examples: - page_info: total: 2 page: 1 per_page: 50 total_pages: 1 queried_range: start_date: '2026-09-01' end_date: '2026-09-30' transactions: - trade_no: '2026090112345678' merchant_out_trade_no: MO202609010001 out_trade_no: 68b5a1c2d3e4f5a6b7c8d9e0 amount: 99.0 paid_status: paid paid_status_label: 已支付 transaction_fee: 1.48 payment_channel: wxpay form_name: 活动报名 form_token: abc123 ordered_at: '2026-09-01T02:10:00Z' paid_at: '2026-09-01T02:10:30Z' TradeTransactionGroup: type: object description: Statistics of one group. Grouped by time, it carries `date`; grouped by payment status, `paid_status` and `label`; grouped by payment channel, `payment_channel` and `label`. required: - transactions_amount - transactions_count - orders_count properties: date: type: string format: date description: 'Start date of the period: the day itself by day, the Monday by week, day 1 of the month by month (the first period starts on the start date of the range)' paid_status: type: string enum: - paid - unpaid - refunded - refunding - partial_refunded payment_channel: type: - string - 'null' enum: - wxpay - alipay - description: Payment channel; null means orders with no payment started label: type: - string - 'null' description: Chinese name of the group value transactions_amount: type: number transactions_count: type: integer orders_count: type: integer TradeTransactionAggregateResponse: type: object required: - queried_range - transactions_amount - transactions_count - orders_count properties: queried_range: $ref: '#/components/schemas/TradeQueriedRange' transactions_amount: type: number description: 'Transaction amount, in yuan (CNY): the amount of paid-type orders minus their own successful refunds' transactions_count: type: integer description: 'Paid count: number of orders that are paid, partially refunded or refunding' orders_count: type: integer description: 'Order count: number of all matching orders, unpaid included' group_by: type: string enum: - time - paid_status - payment_channel description: The grouping dimension used; omitted when not grouped granularity: type: string enum: - day - week - month description: Granularity of the time groups; returned only when `group_by=time` groups: type: array description: Statistics per group; omitted when not grouped items: $ref: '#/components/schemas/TradeTransactionGroup' examples: - queried_range: start_date: '2026-09-01' end_date: '2026-09-07' transactions_amount: 1980.0 transactions_count: 20 orders_count: 23 group_by: payment_channel groups: - payment_channel: wxpay label: 微信 transactions_amount: 1500.0 transactions_count: 15 orders_count: 15 - payment_channel: alipay label: 支付宝 transactions_amount: 480.0 transactions_count: 5 orders_count: 5 - payment_channel: label: transactions_amount: 0.0 transactions_count: 0 orders_count: 3 TradeAmountStats: type: object required: - records_count - amount - by_status properties: records_count: type: integer description: Number of matching records amount: type: number description: Total amount, in yuan (CNY) by_status: type: array description: Count and amount per status, only for statuses that have records items: type: object required: - status - records_count - amount properties: status: type: string enum: - processing - success - error records_count: type: integer amount: type: number description: Total amount for this status, in yuan (CNY) TradeRefundStats: allOf: - $ref: '#/components/schemas/TradeAmountStats' - type: object required: - refunded_orders_count properties: refunded_orders_count: type: integer description: Number of orders with a successful refund; an order refunded several times counts once granularity: type: string enum: - day - week - month description: Period granularity of the trend; returned only when there is a date range trend: type: array description: Trend by refund request date, with zeros for periods without refunds; returned only when there is a date range items: allOf: - $ref: '#/components/schemas/TradeAmountStats' - type: object required: - date - refunded_orders_count properties: date: type: string format: date description: 'Start date of the period: the day itself by day, the Monday by week, day 1 of the month by month (the first period starts on the start date of the range)' refunded_orders_count: type: integer description: Number of orders with a successful refund in this period (deduplicated within the period) TradeRefund: type: object required: - refund_no - trade_no - amount - status - status_description - reason - created_at - refunded_at - refund_transaction_fee - order properties: refund_no: type: - string - 'null' description: Refund reference number trade_no: type: - string - 'null' description: Transaction number of the refunded order amount: type: number description: Refund amount, in yuan (CNY) status: type: string enum: - processing - success - error description: 'Refund status: processing (in progress), success (refunded), error (refund failed)' status_description: type: - string - 'null' description: Status note; the failure reason when the refund failed reason: type: - string - 'null' description: Reason given when the refund was requested created_at: type: - string - 'null' format: date-time description: When the refund was requested refunded_at: type: - string - 'null' format: date-time description: When the refund completed; null when not completed refund_transaction_fee: type: - number - 'null' description: Transaction fee returned with the refund, in yuan (CNY) order: description: The refunded order and its payment form; null when the linked order cannot be found anyOf: - $ref: '#/components/schemas/TradeTransaction' - type: 'null' TradeRefundListResponse: type: object required: - page_info - queried_range - refunds properties: page_info: $ref: '#/components/schemas/TradePageInfo' queried_range: $ref: '#/components/schemas/TradeQueriedRange' refunds: type: - array - 'null' description: Refunds on this page, latest request first; null with `include=stats` or when the detail limit is exceeded items: $ref: '#/components/schemas/TradeRefund' stats: $ref: '#/components/schemas/TradeRefundStats' description: Statistics over all matching refunds; omitted with `include=records` when the detail limit is not exceeded next: type: string description: Number of the next page; pass it back unchanged as the `next` parameter. Omitted when there is no next page detail_limit: type: string description: Why the detail limit was exceeded; omitted when it was not examples: - page_info: total: 1 page: 1 per_page: 50 total_pages: 1 queried_range: start_date: '2026-09-01' end_date: '2026-09-30' refunds: - refund_no: RF2026090100001 trade_no: '2026090112345678' amount: 99.0 status: success status_description: reason: 客户申请退款 created_at: '2026-09-02T01:00:00Z' refunded_at: '2026-09-02T01:00:20Z' refund_transaction_fee: 1.48 order: trade_no: '2026090112345678' merchant_out_trade_no: MO202609010001 out_trade_no: 68b5a1c2d3e4f5a6b7c8d9e0 amount: 99.0 paid_status: refunded paid_status_label: 已退款 transaction_fee: 1.48 payment_channel: wxpay form_name: 活动报名 form_token: abc123 ordered_at: '2026-09-01T02:10:00Z' paid_at: '2026-09-01T02:10:30Z' stats: records_count: 1 amount: 99.0 by_status: - status: success records_count: 1 amount: 99.0 refunded_orders_count: 1 granularity: day trend: - date: '2026-09-01' records_count: 0 amount: 0.0 by_status: [] refunded_orders_count: 0 - date: '2026-09-02' records_count: 1 amount: 99.0 by_status: - status: success records_count: 1 amount: 99.0 refunded_orders_count: 1 TradePayout: type: object required: - amount - status - status_description - created_at - settlement_start_date - settlement_end_date - bank_name - bank_card_no - payout_notes - operation_notes - creator_name properties: amount: type: - number - 'null' description: Payout amount, in yuan (CNY) status: type: string enum: - processing - success - error description: 'Payout status: processing (in progress), success (paid out), error (payout failed)' status_description: type: - string - 'null' description: Status note; the failure reason when the payout failed created_at: type: - string - 'null' format: date-time description: When the payout was requested settlement_start_date: type: - string - 'null' format: date description: First settlement date this payout covers settlement_end_date: type: - string - 'null' format: date description: Last settlement date this payout covers bank_name: type: - string - 'null' description: Receiving bank bank_card_no: type: - string - 'null' description: Receiving bank card number (masked) payout_notes: type: - string - 'null' description: Payout remark operation_notes: type: - string - 'null' description: Operation notes creator_name: type: - string - 'null' description: Name of the person who requested it; their phone number or email when they have no name TradePayoutListResponse: type: object required: - page_info - queried_range - payouts properties: page_info: $ref: '#/components/schemas/TradePageInfo' queried_range: $ref: '#/components/schemas/TradeQueriedRange' payouts: type: - array - 'null' description: Payouts on this page, latest request first; null with `include=stats` or when the detail limit is exceeded items: $ref: '#/components/schemas/TradePayout' stats: $ref: '#/components/schemas/TradeAmountStats' description: Statistics over all matching payouts; omitted with `include=records` when the detail limit is not exceeded next: type: string description: Number of the next page; pass it back unchanged as the `next` parameter. Omitted when there is no next page detail_limit: type: string description: Why the detail limit was exceeded; omitted when it was not examples: - page_info: total: 1 page: 1 per_page: 50 total_pages: 1 queried_range: start_date: '2026-07-03' end_date: '2026-09-30' payouts: - amount: 1500.0 status: success status_description: created_at: '2026-09-10T03:00:00Z' settlement_start_date: '2026-09-01' settlement_end_date: '2026-09-09' bank_name: 招商银行 bank_card_no: 6225********1234 payout_notes: 9 月上旬结算 operation_notes: creator_name: 张三 stats: records_count: 1 amount: 1500.0 by_status: - status: success records_count: 1 amount: 1500.0 TradeMerchant: type: object required: - merchant - subject - contact - balance - settlement - channels - freeze - applied_at - merchant_stage - payment_form_tokens - transactions_amount - rejected_reason - guidance properties: merchant: type: - object - 'null' description: Merchant profile; null when there is no 小金商户 required: - merchant_no - merchant_name - merchant_type - created_at - industry - address - avatar_url properties: merchant_no: type: - string - 'null' description: Merchant number merchant_name: type: - string - 'null' description: Merchant name merchant_type: type: string enum: - business - micro description: 'Merchant type: business (enterprise), micro (micro merchant)' created_at: type: - string - 'null' format: date-time description: When the merchant was activated industry: type: - string - 'null' description: Business category address: type: string description: Business address (region joined with the detailed address) avatar_url: type: - string - 'null' description: Merchant avatar URL subject: type: - object - 'null' description: Legal entity details; null when there is no 小金商户 required: - subject_type - subject_name - license_no - license_image_url - legal_name - legal_licence_no properties: subject_type: type: - string - 'null' description: Entity type code, e.g. `ENTERPRISE` (enterprise), `INDIVIDUAL` (individual business), `INSTITUTION` (public institution / government agency), `COMMUNITY` (social organization), `PEOPLE_RUN_NON_ENTERPRISE` (private non-enterprise unit), `PERSON` (individual, micro merchant) subject_name: type: - string - 'null' description: Entity name license_no: type: - string - 'null' description: Business license number license_image_url: type: - string - 'null' description: Business license image URL legal_name: type: - string - 'null' description: Legal representative's name legal_licence_no: type: - string - 'null' description: Legal representative's ID number (masked) contact: type: - object - 'null' description: Contact details; null when there is no 小金商户 required: - customer_service_phone - customer_service_phone_under_review - manager_name - manager_email - manager_phone properties: customer_service_phone: type: - string - 'null' description: Customer service phone (masked) customer_service_phone_under_review: type: boolean description: Whether a change request for the customer service phone is still under review manager_name: type: - string - 'null' description: Contact name manager_email: type: - string - 'null' description: Contact email (masked) manager_phone: type: - string - 'null' description: Contact mobile number (masked) balance: type: - object - 'null' description: Balance; null when there is no 小金商户 or the balance lookup failed (a failed lookup does not mean the balance is 0) required: - settleable_amount - unsettled_amount properties: settleable_amount: type: - number - 'null' description: Amount available for payout, in yuan (CNY) unsettled_amount: type: - number - 'null' description: Amount awaiting settlement, in yuan (CNY) settlement: type: - object - 'null' description: Settlement details; null when there is no 小金商户 required: - fee_rate - method - bank_name - bank_account_name - bank_card_no - latest_settleable_date properties: fee_rate: type: number description: Fee rate as a percentage (1.49 means 1.49%) method: type: string description: Settlement method, e.g. `D+1 自助结算` bank_name: type: - string - 'null' description: Settlement bank bank_account_name: type: - string - 'null' description: Settlement account name (the entity name) bank_card_no: type: - string - 'null' description: Settlement bank card number (masked) latest_settleable_date: type: - string - 'null' format: date description: Latest settlement date a payout can cover now channels: type: array description: Payment channels the merchant has, and their authorization; an empty array when there is no 小金商户 items: type: object required: - channel - authorized - authorize_state - channel_merchant_no properties: channel: type: - string - 'null' enum: - wxpay - alipay - description: Payment channel authorized: type: boolean description: Whether the channel is authorized; an unauthorized WeChat channel cannot receive WeChat Pay payments authorize_state: type: - string - 'null' enum: - AUTHORIZE_STATE_UNAUTHORIZED - AUTHORIZE_STATE_AUTHORIZED - CLOSED - SMID_NOT_EXIST - description: Channel authorization state code channel_merchant_no: type: - string - 'null' description: Merchant number on the channel freeze: type: - object - 'null' description: Freeze state; null when there is no 小金商户 required: - pay_frozen - pay_frozen_reason - payout_frozen - payout_frozen_reason - yeepay_status - yeepay_status_reasons properties: pay_frozen: type: boolean description: Whether payment collection is frozen pay_frozen_reason: type: - string - 'null' description: Explanation of the payment collection freeze / unfreeze payout_frozen: type: boolean description: Whether payouts are frozen payout_frozen_reason: type: - string - 'null' description: Explanation of the payout freeze / unfreeze yeepay_status: type: - string - 'null' enum: - ACTIVE - FROZEN - OPERATION_EXCEPTION - description: 'Merchant status at the payment provider: ACTIVE (normal), FROZEN (frozen), OPERATION_EXCEPTION (abnormal operation)' yeepay_status_reasons: type: array description: Status reason codes from the payment provider (e.g. `SILENT_MERCHANT`, dormant merchant) items: type: string applied_at: type: - string - 'null' format: date-time description: When the onboarding application was submitted; null when there is no application merchant_stage: type: string enum: - no_application - processing - rejected - pay_frozen - silent - approved_no_form - has_form_no_income - payout_frozen - receiving description: | Onboarding progress: `no_application` not applied yet; `processing` application submitted and under review (merchant not activated yet); `rejected` application rejected (see `rejected_reason`); `pay_frozen` payment collection frozen; `silent` flagged by the payment provider as a dormant merchant with abnormal operation, cannot collect payments until unfrozen; `approved_no_form` merchant activated but no payment form bound yet; `has_form_no_income` payment form bound but no successful payment yet; `payout_frozen` can collect payments but payouts are frozen; `receiving` collecting payments normally. payment_form_tokens: type: array description: Tokens of the payment forms bound to this merchant that the current identity can access (quick payment forms included) items: type: string transactions_amount: type: number description: 'Lifetime transaction amount, in yuan (CNY): the amount of paid-type orders over all time minus successful refunds. For totals by date range or by group, use `GET /trade/transactions/aggregate`' rejected_reason: type: - string - 'null' description: Why the onboarding application was rejected; set only when `merchant_stage` is `rejected` guidance: type: object description: URLs for the next step; null when not applicable required: - register_url - elec_sign_url - wechat_verify_qr_url properties: register_url: type: - string - 'null' format: uri description: URL of the page to apply for onboarding / resubmit after a rejection; set only when `merchant_stage` is `no_application` or `rejected` elec_sign_url: type: - string - 'null' description: E-signing URL; set only when the application has passed review and an enterprise entity is waiting to sign wechat_verify_qr_url: type: - string - 'null' description: QR code URL for WeChat real-name verification; set only when the channel is registered and waiting for WeChat verification examples: - merchant: subject: contact: balance: settlement: channels: [] freeze: applied_at: merchant_stage: no_application payment_form_tokens: [] transactions_amount: 0.0 rejected_reason: guidance: register_url: https://jinshuju.net/trade?openRegister=true elec_sign_url: wechat_verify_qr_url: SMSAuditStatusResponse: type: object required: - signatures properties: signatures: type: array description: The current user's SMS signatures, newest first items: $ref: '#/components/schemas/SMSSignatureAuditStatus' examples: - signatures: - signature: 金数据 status: SUCCESS reason: templates: - content: 您的验证码是#code#,5 分钟内有效。 status: SUCCESS reason: - content: 您报名的活动将于明天开始,请准时参加。 status: FAIL reason: 模板内容缺少签名对应的主体信息 SMSSignatureAuditStatus: type: object required: - signature - status - reason - templates properties: signature: type: string description: Signature text status: type: string enum: - CHECKING - SUCCESS - FAIL description: 'Review status: CHECKING (under review), SUCCESS (approved), FAIL (rejected)' reason: type: - string - 'null' description: Review note; the reason when rejected templates: type: array description: SMS templates under this signature items: $ref: '#/components/schemas/SMSTemplateAuditStatus' SMSTemplateAuditStatus: type: object required: - content - status - reason properties: content: type: - string - 'null' description: Template content status: type: - string - 'null' enum: - CHECKING - SUCCESS - FAIL - description: 'Review status: CHECKING (under review), SUCCESS (approved), FAIL (rejected); null when not yet submitted for review' reason: type: - string - 'null' description: Review note; the reason when rejected BillingAccountInvoice: type: object required: - created_at - amount - organization - dedicated_invoice properties: created_at: type: string format: date-time description: When the e-invoice was requested, ISO 8601 with a time zone offset (Beijing time, UTC+8, e.g. `2024-03-08T14:12:41+08:00`) amount: type: - number - 'null' description: Invoiced amount, in yuan (CNY) to 2 decimal places organization: type: - string - 'null' description: E-invoice title (organization name); null when the title has been deleted dedicated_invoice: type: boolean description: Whether it is a special VAT e-invoice examples: - created_at: '2024-03-08T14:12:41+08:00' amount: 3600.0 organization: 某某科技有限公司 dedicated_invoice: false BillingAccountInvoicesResponse: type: object required: - invoices - uninvoiced_amount properties: invoices: type: object required: - count - records properties: count: type: integer description: Number of e-invoices records: type: array description: Latest request first items: $ref: '#/components/schemas/BillingAccountInvoice' uninvoiced_amount: type: object description: Spending that can be invoiced but has not been invoiced yet required: - total - transaction_count properties: total: type: number description: Total uninvoiced amount, in yuan (CNY) to 2 decimal places transaction_count: type: integer description: Number of uninvoiced spending records BillingAccountPaymentHistory: type: object required: - id - created_at - verb - description - amount - balance properties: id: type: string description: Record ID created_at: type: string format: date-time description: When it happened, ISO 8601 with a time zone offset (Beijing time, UTC+8, e.g. `2024-03-13T17:20:11+08:00`) verb: type: string description: Record type; see the `verb` parameter for the values description: type: - string - 'null' description: Record description, generated per record type (such as the name of the plan purchased, the number of SMS messages, the number of members); null when there is none amount: type: - number - 'null' description: Amount, in yuan (CNY) to 2 decimal places; positive for top-ups, negative for spending balance: type: - number - 'null' description: Account balance after this record, in yuan (CNY) to 2 decimal places examples: - id: 65f1c2a3b4c5d6e7f8a9b0c1 created_at: '2024-03-13T17:20:11+08:00' verb: sms_charge description: 购买短信 amount: -100.0 balance: 900.0 BillingAccountBalance: type: object description: Account balance and the remaining amount of each quota (plan + purchased) required: - amount - entry_quota - sms_count - ai_points_count - active_mail_count - storage_quota_count - audio_quota_count - entry_transaction_quota_count properties: amount: type: - number - 'null' description: Account balance, in yuan (CNY) to 2 decimal places entry_quota: type: integer description: Entries remaining this month sms_count: type: integer description: SMS messages remaining ai_points_count: type: integer description: AI points remaining active_mail_count: type: integer description: Emails remaining storage_quota_count: type: number description: Attachment storage remaining (MB, may be fractional) audio_quota_count: type: integer description: Voice time remaining (minutes, rounded from seconds) entry_transaction_quota_count: type: - number - string description: Payment collection quota remaining, in yuan (CNY) to 2 decimal places; the string `无限额` when the plan has no limit examples: - amount: 900.0 entry_quota: 9800 sms_count: 1200 ai_points_count: 500 active_mail_count: 300 storage_quota_count: 2048 audio_quota_count: 60 entry_transaction_quota_count: 无限额 BillingAccountPaymentStatistics: type: object description: Summary of the records returned in this response required: - total_consumption - total_recharge - verb_distribution properties: total_consumption: type: number description: Total spending, in yuan (CNY), as a positive number total_recharge: type: number description: Total top-ups, in yuan (CNY) verb_distribution: type: object description: Record count per type, keyed by `verb` additionalProperties: type: integer examples: - total_consumption: 200.0 total_recharge: 1000.0 verb_distribution: charge: 1 sms_charge: 2 BillingAccountPaymentHistoriesResponse: type: object required: - payment_history properties: payment_history: type: object required: - total_records - returned_records - records properties: total_records: type: integer description: Total records matching the conditions returned_records: type: integer description: Number returned this time records: type: array description: Latest first items: $ref: '#/components/schemas/BillingAccountPaymentHistory' current_balance: $ref: '#/components/schemas/BillingAccountBalance' description: Present only when `include_balance=true` statistics: $ref: '#/components/schemas/BillingAccountPaymentStatistics' description: Present only when this response returns records RelationFieldInput: type: object title: RelationFieldInput description: RelationField field additionalProperties: false required: - type - label properties: type: const: RelationField label: type: string description: Field label cid: type: string description: Temporary id within this request, for formulas and the like to refer to notes: type: string description: Field notes private: type: boolean description: Hidden field; a hidden field is not checked for required required: type: boolean description: Required position: type: integer minimum: 0 description: Target position of the field in the form, from 0; appended at the end by default related_form_token: type: string description: Token of the related table; must be another table, and you need manage permission on it paired: type: boolean description: Two-way relation, on by default; when on, a reverse column is created in the related table related_label: type: string description: Name of the reverse column, used only when the reverse column is created; defaults to the name of this table GoodsItemUpdateInput: type: object title: GoodsItemUpdateInput additionalProperties: false description: A goods item; one with api_code is an existing item and keeps whatever it leaves out properties: name: type: string description: Goods name layout: type: string enum: - without_images - price_only - images - text_options description: Layout api_code: type: string description: Keeps the identity of the item on edit; when left out, an existing item is matched by name description: type: string description: Goods description position: type: integer minimum: 0 hidden: type: boolean price: type: number minimum: 0 original_price: type: number minimum: 0 description: Original price, shown struck through predefined_number: type: integer minimum: 0 description: Default quantity fixed_number: type: boolean description: The quantity cannot be changed inventory: type: integer minimum: 0 description: Stock; with specifications, set it on each sku instead inventory_reset: type: boolean min_purchase_quantity: type: integer minimum: 0 max_purchase_quantity: type: integer minimum: 0 dimensions: type: array minItems: 1 items: type: object additionalProperties: false required: - label - options properties: api_code: type: string description: Keeps the identity on edit label: type: string description: Dimension name, such as `尺寸` options: type: array minItems: 1 items: type: object additionalProperties: false required: - label properties: label: type: string value: type: string description: Generated when left out; customized marks a custom amount option description: Specification dimensions skus: type: array minItems: 1 items: type: object additionalProperties: false required: - specification properties: specification: type: object additionalProperties: type: string description: Keyed by dimension api_code or name; each value is an option value or name price: type: number minimum: 0 original_price: type: number minimum: 0 inventory: type: integer minimum: 0 inventory_reset: type: boolean min_purchase_quantity: type: integer minimum: 0 max_purchase_quantity: type: integer minimum: 0 description: Specification combinations; specification must name one option for every dimension image_urls: type: array items: type: string format: uri description: Goods image URLs for layout=images image_base64s: type: array items: type: string description: Base64 goods images for layout=images dependentRequired: dimensions: - skus skus: - dimensions if: not: required: - api_code then: required: - name - layout allOf: - description: The price_only / text_options layouts require specifications if: properties: layout: enum: - price_only - text_options then: required: - dimensions - skus - description: The images layout needs at least one image if: properties: layout: const: images then: anyOf: - required: - image_urls properties: image_urls: minItems: 1 - required: - image_base64s properties: image_base64s: minItems: 1