Skip to main content
View as Markdown

Batch Operations

Batch endpoints write many records in a single request, so you can import, synchronize, or modify bulk data efficiently — and atomically. Each batch runs in a single transaction: if any record fails validation, the whole batch rolls back and no rows are written. Pass returnRecords: true to receive the affected records in the response (otherwise only a summary is returned).

Method & Path Operation Max per batch
POST /api/tables/:tableId/records/batch Create 1000
PATCH /api/tables/:tableId/records/batch Update 100
DELETE /api/tables/:tableId/records/batch Soft delete 100
POST /api/tables/:tableId/records/batch/restore Restore 100
POST /api/tables/:tableId/records/upsert Upsert 100

All batch bodies require the canonical envelope form ({ "fields": { ... } }) — the flat-body shorthand accepted by single-record create is not available in batch requests. Every batch must contain at least one record.

Batch create

Send a records array, each item an envelope. Up to 1000 records per call.

POST /api/tables/contacts/records/batch
{
  "records": [
    { "fields": { "email": "alice@example.com", "name": "Alice" } },
    { "fields": { "email": "bob@example.com", "name": "Bob" } }
  ],
  "returnRecords": true
}
Status Meaning
201 Created All records created
400 Bad Request Empty array, over the 1000 limit, or any record fails validation (whole batch rolls back)
401 Unauthorized No active session
404 Not Found Table not found or not visible

Batch update

Each item names the record id (string or number) plus the fields to patch. Up to 100 records per call.

PATCH /api/tables/contacts/records/batch
{
  "records": [
    { "id": "1", "fields": { "status": "active" } },
    { "id": 2, "fields": { "status": "archived" } }
  ],
  "returnRecords": true
}

Updates are partial per record — only the named fields are written. If any id is missing or any value is invalid, the transaction rolls back.

Batch delete

Send an ids array. Soft delete by default; set permanent: true to hard-delete already soft-deleted records (admin-only, enforced in the application layer). Up to 100 IDs per call.

DELETE /api/tables/contacts/records/batch
{
  "ids": ["1", "2", 3],
  "permanent": false
}

Batch restore

Recover many soft-deleted records at once. Records that are not currently deleted are skipped; a missing id rolls the whole batch back.

POST /api/tables/contacts/records/batch/restore
{
  "ids": ["1", "2", "3"]
}

The restore clears each record's deletedAt/deletedBy and is logged to the record's change history.

Batch upsert

Create-or-update many records matched on one or more unique fields, in a single transaction. Name the merge key(s) with fieldsToMergeOn (alias: matchFields). Up to 100 records per call.

POST /api/tables/contacts/records/upsert
{
  "records": [
    { "fields": { "email": "alice@example.com", "name": "Alice" } },
    { "fields": { "email": "carol@example.com", "name": "Carol" } }
  ],
  "fieldsToMergeOn": ["email"],
  "returnRecords": true
}

Each record is matched on the merge fields: an existing match is patched, otherwise a new row is created. Batch upsert is the canonical path for idempotent synchronization from an external source of truth.

Limits & semantics summary

Property Behavior
Atomicity Each batch is a single transaction — all-or-nothing
returnRecords false by default; true returns the affected records
Minimum size At least one record/ID required (400 otherwise)
Authorship createdBy/updatedBy/deletedBy stamped per record, same as single writes
Permissions RBAC and field-level permissions enforced per record