Grist records API
Tables contain collections of records (also called rows).
Tables contain collections of records (also called rows).
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/grist-records-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
description: 'An API for manipulating Grist sites, workspaces, and documents.
# Authentication
<SecurityDefinitions />
'
version: 1.0.1
title: Grist attachments Records API
servers:
- url: https://{gristhost}/api
variables:
subdomain:
description: The team name, or `docs` for personal areas
default: docs
security:
- ApiKey: []
tags:
- name: records
description: Tables contain collections of records (also called rows).
paths:
/docs/{docId}/tables/{tableId}/records:
get:
operationId: listRecords
tags:
- records
summary: Fetch records from a table
parameters:
- $ref: '#/components/parameters/docIdPathParam'
- $ref: '#/components/parameters/tableIdPathParam'
- $ref: '#/components/parameters/filterQueryParam'
- $ref: '#/components/parameters/sortQueryParam'
- $ref: '#/components/parameters/limitQueryParam'
- $ref: '#/components/parameters/sortHeaderParam'
- $ref: '#/components/parameters/limitHeaderParam'
- $ref: '#/components/parameters/hiddenQueryParam'
responses:
200:
description: Records from the table
content:
application/json:
schema:
$ref: '#/components/schemas/RecordsList'
post:
operationId: addRecords
tags:
- records
summary: Add records to a table
parameters:
- $ref: '#/components/parameters/docIdPathParam'
- $ref: '#/components/parameters/tableIdPathParam'
- $ref: '#/components/parameters/noparseQueryParam'
requestBody:
description: the records to add
content:
application/json:
schema:
$ref: '#/components/schemas/RecordsWithoutId'
required: true
responses:
200:
description: IDs of records added
content:
application/json:
schema:
$ref: '#/components/schemas/RecordsWithoutFields'
patch:
operationId: modifyRecords
tags:
- records
summary: Modify records of a table
parameters:
- $ref: '#/components/parameters/docIdPathParam'
- $ref: '#/components/parameters/tableIdPathParam'
- $ref: '#/components/parameters/noparseQueryParam'
requestBody:
description: the records to change, with ids
content:
application/json:
schema:
$ref: '#/components/schemas/RecordsList'
required: true
responses:
200:
description: Success
put:
operationId: replaceRecords
tags:
- records
summary: Add or update records of a table
parameters:
- $ref: '#/components/parameters/docIdPathParam'
- $ref: '#/components/parameters/tableIdPathParam'
- $ref: '#/components/parameters/noparseQueryParam'
- in: query
name: onmany
schema:
type: string
enum:
- first
- none
- all
description: "Which records to update if multiple records are found to match `require`.\n * `first` - the first matching record (default)\n * `none` - do not update anything\n * `all` - update all matches\n"
- in: query
name: noadd
schema:
type: boolean
description: Set to true to prohibit adding records.
- in: query
name: noupdate
schema:
type: boolean
description: Set to true to prohibit updating records.
- in: query
name: allow_empty_require
schema:
type: boolean
description: Set to true to allow `require` in the body to be empty, which will match and update all records in the table.
requestBody:
description: 'The records to add or update. Instead of an id, a `require` object is provided, with the same structure as `fields`. If no query parameter options are set, then the operation is as follows. First, we check if a record exists matching the values specified for columns in `require`. If so, we update it by setting the values specified for columns in `fields`. If not, we create a new record with a combination of the values in `require` and `fields`, with `fields` taking priority if the same column is specified in both. The query parameters allow for variations on this behavior.
'
content:
application/json:
schema:
$ref: '#/components/schemas/RecordsWithRequire'
required: true
responses:
200:
description: Success
/docs/{docId}/tables/{tableId}/records/delete:
post:
operationId: deleteRecords
tags:
- records
summary: Delete records of a table
parameters:
- $ref: '#/components/parameters/docIdPathParam'
- $ref: '#/components/parameters/tableIdPathParam'
requestBody:
description: the IDs of records to remove
content:
application/json:
schema:
$ref: '#/components/schemas/RowIds'
required: true
responses:
200:
description: Nothing returned
components:
parameters:
docIdPathParam:
in: path
name: docId
schema:
type: string
description: A string id (UUID)
required: true
hiddenQueryParam:
in: query
name: hidden
schema:
type: boolean
description: Set to true to include the hidden columns (like "manualSort")
sortHeaderParam:
in: header
name: X-Sort
schema:
type: string
description: Same as `sort` query parameter.
example: pet,-age
required: false
tableIdPathParam:
in: path
name: tableId
schema:
type: string
description: normalized table name (see `TABLE ID` in Raw Data) or numeric row ID in `_grist_Tables`
required: true
limitQueryParam:
in: query
name: limit
schema:
type: number
description: Return at most this number of rows. A value of 0 is equivalent to having no limit.
example: '5'
required: false
sortQueryParam:
in: query
name: sort
schema:
type: string
description: 'Order in which to return results. If a single column name is given (e.g. `pet`), results are placed in ascending order of values in that column. To get results in an order that was previously prepared manually in Grist, use the special `manualSort` column name. Multiple columns can be specified, separated by commas (e.g. `pet,age`). For descending order, prefix a column name with a `-` character (e.g. `pet,-age`). To include additional sorting options append them after a colon (e.g. `pet,-age:naturalSort;emptyLast,owner`). Available options are: `orderByChoice`, `naturalSort`, `emptyLast`. Without the `sort` parameter, the order of results is unspecified.'
example: pet,-age
required: false
noparseQueryParam:
in: query
name: noparse
schema:
type: boolean
description: Set to true to prohibit parsing strings according to the column type.
limitHeaderParam:
in: header
name: X-Limit
schema:
type: number
description: Same as `limit` query parameter.
example: '5'
required: false
filterQueryParam:
in: query
name: filter
schema:
type: string
description: 'This is a JSON object mapping column names to arrays of allowed values. For example, to filter column `pet` for values `cat` and `dog`, the filter would be `{"pet": ["cat", "dog"]}`. JSON contains characters that are not safe to place in a URL, so it is important to url-encode them. For this example, the url-encoding is `%7B%22pet%22%3A%20%5B%22cat%22%2C%20%22dog%22%5D%7D`. See https://rosettacode.org/wiki/URL_encoding for how to url-encode a string, or https://www.urlencoder.org/ to try some examples. Multiple columns can be filtered. For example the filter for `pet` being either `cat` or `dog`, AND `size` being either `tiny` or `outrageously small`, would be `{"pet": ["cat", "dog"], "size": ["tiny", "outrageously small"]}`.'
example: '{"pet": ["cat", "dog"]}'
required: false
schemas:
RecordsWithoutId:
type: object
required:
- records
properties:
records:
type: array
items:
type: object
required:
- fields
properties:
fields:
type: object
description: A JSON object mapping column names to [cell values](https://support.getgrist.com/code/modules/GristData/#cellvalue).
example:
records:
- fields:
pet: cat
popularity: 67
- fields:
pet: dog
popularity: 95
RowIds:
type: array
example:
- 101
- 102
- 103
items:
type: integer
RecordsList:
type: object
required:
- records
properties:
records:
type: array
items:
type: object
required:
- id
- fields
properties:
id:
type: number
example: 1
fields:
type: object
description: A JSON object mapping column names to [cell values](https://support.getgrist.com/code/modules/GristData/#cellvalue).
example:
records:
- id: 1
fields:
pet: cat
popularity: 67
- id: 2
fields:
pet: dog
popularity: 95
RecordsWithoutFields:
type: object
required:
- records
properties:
records:
type: array
items:
type: object
required:
- id
properties:
id:
type: number
example: 1
example:
records:
- id: 1
- id: 2
RecordsWithRequire:
type: object
required:
- records
properties:
records:
type: array
items:
type: object
required:
- require
properties:
require:
type: object
description: 'keys are column identifiers, and values are [cell values](https://support.getgrist.com/code/modules/GristData/#cellvalue) we want to have in those columns (either by matching with an existing record, or creating a new record)
'
fields:
type: object
description: 'keys are column identifiers, and values are [cell values](https://support.getgrist.com/code/modules/GristData/#cellvalue) to place in those columns (either overwriting values in an existing record, or in a new record)
'
example:
records:
- require:
pet: cat
fields:
popularity: 67
- require:
pet: dog
fields:
popularity: 95
securitySchemes:
ApiKey:
type: http
scheme: bearer
bearerFormat: 'Authorization: Bearer XXXXXXXXXXX'
description: Access to the Grist API is controlled by an Authorization header, which should contain the word 'Bearer', followed by a space, followed by your API key.