Skip to content
Syncline

Airtable API reference

<p>These are the Syncline endpoints for the Airtable connector. Every route runs on the Syncline API, takes a Syncline key, and returns the Syncline response shape. This page is not a copy of Airtable's Web API and the paths here do not exist on Airtable's side: for the vendor routes, read Airtable's own developer documentation.</p><p>The connector reads and writes only the bases you selected when you authorised it. Field types are respected in both directions, so numbers keep their precision, dates keep their timezone and a single select that receives an unknown option is reported back to you rather than written blind. Batch writes are grouped ten records at a time to stay inside Airtable's per base budget.</p>
Base URL: https://api.syncline.topclb.com

Authentication

Send a Syncline secret key as a bearer token: Authorization: Bearer sk_live_... . The connection_id parameter selects the authorised base group. Both OAuth connections and personal access tokens are supported at the connection level, and the API surface is identical either way, so switching later needs no code change.

Endpoints

<article class="sy-endpoint"><h3><code>GET /v1/connectors/airtable/records</code></h3><p>Read records from a table or a view, with the view's own filter applied.</p><div class="sy-table-wrap"><table><thead><tr><th>Param</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>connection_id</td><td>string</td><td>yes</td><td>The authorised Airtable connection to read through.</td></tr><tr><td>base_id</td><td>string</td><td>yes</td><td>The base to read from, for example appK71c2Fq9Le0Xd.</td></tr><tr><td>table</td><td>string</td><td>yes</td><td>Table name or ID.</td></tr><tr><td>view</td><td>string</td><td>no</td><td>View name. Supplying it inherits the filter your team already maintains in Airtable.</td></tr><tr><td>limit</td><td>integer</td><td>no</td><td>Results per page, 1 to 100. Defaults to 50.</td></tr></tbody></table></div><pre><code>{ &quot;run_id&quot;: &quot;run_09db7594&quot;, &quot;connector&quot;: &quot;airtable&quot;, &quot;status&quot;: &quot;ok&quot;, &quot;data&quot;: [ { &quot;record_id&quot;: &quot;recQ4m81tVbZa0Kx&quot;, &quot;fields&quot;: { &quot;Name&quot;: &quot;Harbour Line Coffee&quot;, &quot;Status&quot;: &quot;Ready&quot;, &quot;Amount&quot;: 4900, &quot;Owner&quot;: &quot;marcus@syncline.topclb.com&quot; }, &quot;created_at&quot;: &quot;2026-09-06T16:04:55Z&quot; } ], &quot;next_cursor&quot;: &quot;recQ4m81tVbZa0Kx&quot; }</code></pre></article><article class="sy-endpoint"><h3><code>POST /v1/connectors/airtable/records</code></h3><p>Create up to ten records in one call, with per record success reported.</p><div class="sy-table-wrap"><table><thead><tr><th>Param</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>connection_id</td><td>string</td><td>yes</td><td>The authorised Airtable connection to write through.</td></tr><tr><td>base_id</td><td>string</td><td>yes</td><td>The base that holds the target table.</td></tr><tr><td>table</td><td>string</td><td>yes</td><td>Table name or ID.</td></tr><tr><td>records</td><td>array</td><td>yes</td><td>One to ten objects of field name to value. Rejected as a whole when the array is longer.</td></tr><tr><td>allow_new_options</td><td>boolean</td><td>no</td><td>Let a select field gain an option it does not have yet. Defaults to false, which fails loudly instead.</td></tr></tbody></table></div><pre><code>{ &quot;run_id&quot;: &quot;run_1aec86a5&quot;, &quot;connector&quot;: &quot;airtable&quot;, &quot;status&quot;: &quot;partial&quot;, &quot;data&quot;: { &quot;created&quot;: [&quot;recB19zPd3Yn7Wcq&quot;], &quot;failed&quot;: [ { &quot;index&quot;: 1, &quot;error&quot;: &quot;select_option_missing&quot;, &quot;field&quot;: &quot;Status&quot;, &quot;value&quot;: &quot;Ready for review&quot; } ] } }</code></pre></article><article class="sy-endpoint"><h3><code>PATCH /v1/connectors/airtable/records/{record_id}</code></h3><p>Update the fields you name on one record, leaving the rest untouched.</p><div class="sy-table-wrap"><table><thead><tr><th>Param</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>connection_id</td><td>string</td><td>yes</td><td>The authorised Airtable connection to write through.</td></tr><tr><td>base_id</td><td>string</td><td>yes</td><td>The base that holds the record.</td></tr><tr><td>table</td><td>string</td><td>yes</td><td>Table name or ID.</td></tr><tr><td>fields</td><td>object</td><td>yes</td><td>Field name to value. Formula and rollup fields are read only and are refused here.</td></tr></tbody></table></div><pre><code>{ &quot;run_id&quot;: &quot;run_2bfd97b6&quot;, &quot;connector&quot;: &quot;airtable&quot;, &quot;status&quot;: &quot;ok&quot;, &quot;data&quot;: { &quot;record_id&quot;: &quot;recQ4m81tVbZa0Kx&quot;, &quot;updated_fields&quot;: [&quot;Status&quot;, &quot;Amount&quot;], &quot;updated_at&quot;: &quot;2026-09-07T11:21:38Z&quot; } }</code></pre></article><article class="sy-endpoint"><h3><code>POST /v1/connectors/airtable/attachments</code></h3><p>Attach a file to a record from a public link or an uploaded file.</p><div class="sy-table-wrap"><table><thead><tr><th>Param</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>connection_id</td><td>string</td><td>yes</td><td>The authorised Airtable connection to write through.</td></tr><tr><td>record_id</td><td>string</td><td>yes</td><td>The record that will hold the attachment.</td></tr><tr><td>field</td><td>string</td><td>yes</td><td>The attachment field name on that table.</td></tr><tr><td>url</td><td>string</td><td>yes</td><td>A publicly reachable link. Syncline streams the file rather than loading it into memory.</td></tr><tr><td>filename</td><td>string</td><td>no</td><td>Override the name shown in Airtable. Defaults to the last path segment of the URL.</td></tr></tbody></table></div><pre><code>{ &quot;run_id&quot;: &quot;run_3c0ea8c7&quot;, &quot;connector&quot;: &quot;airtable&quot;, &quot;status&quot;: &quot;ok&quot;, &quot;data&quot;: { &quot;record_id&quot;: &quot;recQ4m81tVbZa0Kx&quot;, &quot;field&quot;: &quot;Documents&quot;, &quot;attachment_id&quot;: &quot;attR7v20Kc9dLm3s&quot;, &quot;filename&quot;: &quot;invoice-20481.pdf&quot;, &quot;size_bytes&quot;: 184320 } }</code></pre></article><article class="sy-endpoint"><h3><code>GET /v1/connectors/airtable/tables</code></h3><p>List tables, views and field types in a base, for building a mapping.</p><div class="sy-table-wrap"><table><thead><tr><th>Param</th><th>Type</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>connection_id</td><td>string</td><td>yes</td><td>The authorised Airtable connection to inspect.</td></tr><tr><td>base_id</td><td>string</td><td>yes</td><td>The base to describe.</td></tr><tr><td>include_views</td><td>boolean</td><td>no</td><td>Include the view list on each table. Defaults to true.</td></tr></tbody></table></div><pre><code>{ &quot;run_id&quot;: &quot;run_4d1fb9d8&quot;, &quot;connector&quot;: &quot;airtable&quot;, &quot;status&quot;: &quot;ok&quot;, &quot;data&quot;: [ { &quot;table&quot;: &quot;Orders&quot;, &quot;table_id&quot;: &quot;tblM3s90PqVn1Zdc&quot;, &quot;primary_field&quot;: &quot;Name&quot;, &quot;fields&quot;: [ { &quot;name&quot;: &quot;Status&quot;, &quot;type&quot;: &quot;singleSelect&quot; }, { &quot;name&quot;: &quot;Amount&quot;, &quot;type&quot;: &quot;number&quot; } ], &quot;views&quot;: [&quot;Grid view&quot;, &quot;Ready&quot;] } ] }</code></pre></article>

Errors

<div class="sy-table-wrap"><table><thead><tr><th>Code</th><th>Meaning</th><th>What to do</th></tr></thead><tbody><tr><td>401 connection_revoked</td><td>The OAuth grant or personal access token behind this connection is no longer valid.</td><td>Reconnect from Connections, or issue a fresh token and paste it in. Base selections are remembered.</td></tr><tr><td>403 base_not_selected</td><td>The base exists but was not included when the connection was authorised.</td><td>Edit the connection and tick that base. Nothing outside the selection is ever readable to us.</td></tr><tr><td>404 field_not_found</td><td>A field name in the request does not exist on the table, most often after a rename in Airtable.</td><td>Call the tables route to read the current field list, then update the mapping to the new name.</td></tr><tr><td>422 select_option_missing</td><td>A single or multi select received a value that is not one of its options, and we do not write blind.</td><td>Add the option in Airtable, set allow_new_options to true, or translate the value before sending it.</td></tr><tr><td>429 upstream_rate_limited</td><td>Airtable's per base budget of about five requests per second was reached.</td><td>Group writes into the ten record batch endpoint, or lower the backfill rate until the window clears.</td></tr></tbody></table></div>

Rate limits

Syncline allows 120 requests per minute per API key. Airtable allows roughly five requests per second per base, so the batch create route is worth using whenever you have more than one record: ten records in one call costs one request against both budgets. A partial batch returns status partial with a per record failure list rather than failing the whole call.

Code samples

<h4>curl</h4><pre><code>curl -X POST https://api.syncline.topclb.com/v1/connectors/airtable/records \ -H &quot;Authorization: Bearer $SYNCLINE_KEY&quot; \ -H &quot;Content-Type: application/json&quot; \ -d '{ &quot;connection_id&quot;: &quot;con_airtable_5t4&quot;, &quot;base_id&quot;: &quot;appK71c2Fq9Le0Xd&quot;, &quot;table&quot;: &quot;Orders&quot;, &quot;records&quot;: [ { &quot;Name&quot;: &quot;Harbour Line Coffee&quot;, &quot;Status&quot;: &quot;Ready&quot;, &quot;Amount&quot;: 4900 } ] }'</code></pre><h4>node</h4><pre><code>const res = await fetch( &quot;https://api.syncline.topclb.com/v1/connectors/airtable/records&quot;, { method: &quot;POST&quot;, headers: { Authorization: `Bearer ${process.env.SYNCLINE_KEY}`, &quot;Content-Type&quot;: &quot;application/json&quot; }, body: JSON.stringify({ connection_id: &quot;con_airtable_5t4&quot;, base_id: &quot;appK71c2Fq9Le0Xd&quot;, table: &quot;Orders&quot;, records: [{ Name: &quot;Harbour Line Coffee&quot;, Status: &quot;Ready&quot; }] }) } ); const { data } = await res.json(); console.log(data.created.length, &quot;created&quot;);</code></pre><h4>python</h4><pre><code>import os import requests resp = requests.post( &quot;https://api.syncline.topclb.com/v1/connectors/airtable/records&quot;, headers={&quot;Authorization&quot;: f&quot;Bearer {os.environ['SYNCLINE_KEY']}&quot;}, json={ &quot;connection_id&quot;: &quot;con_airtable_5t4&quot;, &quot;base_id&quot;: &quot;appK71c2Fq9Le0Xd&quot;, &quot;table&quot;: &quot;Orders&quot;, &quot;records&quot;: [{&quot;Name&quot;: &quot;Harbour Line Coffee&quot;, &quot;Status&quot;: &quot;Ready&quot;}], }, timeout=30, ) resp.raise_for_status() print(resp.json()[&quot;data&quot;][&quot;created&quot;])</code></pre>