The records API
The records API is a plain JSON CRUD interface over a table, for clients that don’t want to
speak Esri. Same data, same permissions, same write pipeline as
applyEdits — but GeoJSON in, GeoJSON out, and records
addressed by their provider record key (an Airtable recXXX, a NocoDB row id, a SQL
primary key) rather than a derived OBJECTID.
/api/v0/bases/{baseId}/tables/{tableName}/recordsReads need viewer access to the base (or a public base); writes need write access — an org
member role or better, or an API key with write permission.
curl 'https://{SERVER}/api/v0/bases/appXXX/tables/Locations/records' \ --get \ --data-urlencode "where=Status = 'Open'" \ --data-urlencode 'outFields=Name,Status,Capacity' \ --data-urlencode 'orderByFields=Name ASC' \ --data-urlencode 'limit=50' \ -H 'Authorization: Bearer ims_…'| Parameter | Meaning |
|---|---|
where |
SQL-92 subset, same dialect as the FeatureServer. 1=1 is treated as no filter. |
outFields |
Comma-separated field list. Omit for everything. |
bbox |
minX,minY,maxX,maxY — features contained by the box. |
limit, offset |
Paging. |
orderByFields |
Field ASC, Other DESC. |
The response is a GeoJSON FeatureCollection. With no parameters at all you get the cached
collection verbatim, which is the fastest possible read.
One record
Section titled “One record”GET /api/v0/bases/{baseId}/tables/{tableName}/records/{OBJECTID}Note the asymmetry, which trips people up: reads by id take the OBJECTID; writes take the provider record key. Reads are served from the cache, which is indexed by OBJECTID; writes go to the provider, which only knows its own key.
Create
Section titled “Create”curl -X POST '…/records' \ -H 'Content-Type: application/json' -H 'Authorization: Bearer ims_…' \ -d '{ "features": [ { "attributes": { "Name": "New site", "Status": "Open" }, "geometry": { "x": -77.03, "y": 38.90 } } ] }'{ "successes": [{ "id": "recAbC123", "success": true }], "errors": [] }201 when anything was created, 400 when the payload was bad, 500 when the provider
refused. id in each success is the new provider record key — keep it, it’s how you’ll address
the record from here on.
Update
Section titled “Update”curl -X PATCH '…/records/recAbC123' \ -H 'Content-Type: application/json' -H 'Authorization: Bearer ims_…' \ -d '{ "attributes": { "Status": "Closed" }, "geometry": { "x": -77.03, "y": 38.90 } }'A partial update — only the fields you send are touched. geometry is optional. Returns
{ "success": true, "id": "recAbC123", "fields": { … } }.
Delete
Section titled “Delete”curl -X DELETE '…/records/recAbC123' -H 'Authorization: Bearer ims_…'Permanent upstream, but the record’s history — including a full before-snapshot — stays in the activity log, and the record can be restored from it.
Rules that apply to every write
Section titled “Rules that apply to every write”- The provider must be writable —
fetchandtsipbases reject edits. - Read-only fields (formulas, rollups, lookups, autonumbers, created/modified stamps) are rejected, not silently dropped.
- Writes are serialized per table by a distributed write lock.
- The cache is updated in place, so the next read is correct immediately.
- The change is logged with a before-snapshot and broadcast on the realtime feed.
- In
READ_ONLYorCACHE_ONLYmode the server answers 503 rather than writing.
Attachments
Section titled “Attachments”Attachment cells are not edited through this API — they have their own endpoints, because the payload is file bytes. See Attachments.