Your transport management system, ERP, or shop already knows the latest rates, zones, and stock. Push them into a Formspring data table whenever they change, so your forms always quote from current numbers. You can also let an AI agent manage tables with MCP tools.
Base URL: https://formspring.io/api/v1. Requests use a bearer token; see API authentication.
Token abilities
| Ability | Lets the token |
|---|---|
data-tables:read |
List tables, read table details, and page through rows. |
data-tables:write |
Create, rename, and delete tables, and push rows. |
A token only ever sees the tables of its own workspace. Asking for another workspace's table answers 404.
1. Create a table
curl -X POST https://formspring.io/api/v1/data-tables \
-H "Authorization: Bearer your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Pallet rates 2026",
"slug": "pallet_rates",
"columns": ["max_kg", "price"]
}'
You can add "rows": [...] to load the first rows in the same call. The response is the table: id, name, slug, columns, row_count, and pushable (true when you can push rows into it).
2. Replace the whole table
PUT swaps the complete contents in one step. Send it every time your system exports the full rate card. The same body always gives the same result, so a retry is safe.
curl -X PUT https://formspring.io/api/v1/data-tables/TABLE_ID/rows \
-H "Authorization: Bearer your-api-token" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{ "max_kg": 100, "price": 40 },
{ "max_kg": 500, "price": 90 },
{ "max_kg": 1000, "price": 150 }
]
}'
- Each row is an object keyed by column name. Cells can be text, numbers, or empty. A missing cell is stored blank.
- Add
"columns": ["max_kg", "price"]to change the columns as well. Without it, the table keeps its current columns. - Text is cleaned the same way as a CSV upload:
"12.50"becomes the number 12.5, and"01234"stays text. - An empty
"rows": []clears the table. - If anything in the request is invalid, nothing changes and the old rows stay in place.
3. Update a few rows
POST updates the rows whose key column matches and adds the rest. Cells you leave out of an existing row keep their value.
curl -X POST https://formspring.io/api/v1/data-tables/TABLE_ID/rows \
-H "Authorization: Bearer your-api-token" \
-H "Content-Type: application/json" \
-d '{
"key_column": "max_kg",
"rows": [
{ "max_kg": 500, "price": 95 },
{ "max_kg": 2000, "price": 300 }
]
}'
The response says how many rows were added and updated (table details abbreviated):
{ "data": { "row_count": 4 }, "meta": { "created": 1, "updated": 1 } }
The key column must exist, every pushed row needs a value in it, and a key may appear only once per request. Keys match the way formulas do: capital letters and spaces are ignored, numbers compare as numbers.
4. Read it back
curl -H "Authorization: Bearer your-api-token" \
"https://formspring.io/api/v1/data-tables/TABLE_ID/rows?per_page=100&page=1"
Pages hold up to 100 rows (50 by default). meta gives total and last_page. GET /data-tables lists your tables and GET /data-tables/TABLE_ID shows one with its columns and row count.
Rename or delete
curl -X PATCH https://formspring.io/api/v1/data-tables/TABLE_ID \
-H "Authorization: Bearer your-api-token" \
-H "Content-Type: application/json" \
-d '{ "name": "Pallet rates 2027", "slug": "pallet_rates" }'
curl -X DELETE https://formspring.io/api/v1/data-tables/TABLE_ID \
-H "Authorization: Bearer your-api-token"
Changing the slug means formulas that use the old one stop finding the table, so update the forms too. Delete answers 202 because the removal runs in the background.
Limits
| Limit | Value |
|---|---|
| Rows per table | 5,000 (the table after an upsert counts too) |
| Columns per table | 20 |
| Request body | 1 MB (larger requests answer 413) |
| Rows per page when reading | 100 |
| Push requests | 10 per minute per token; other calls share the standard API limit. Responses carry X-RateLimit-* headers. |
Errors
| Status | Meaning |
|---|---|
403 |
The token is missing data-tables:read or data-tables:write. |
404 |
No such table in this workspace. |
409 |
The table refreshes from an API (see here), so it cannot be pushed to. |
413 |
The request is larger than 1 MB. Split it into smaller pushes. |
422 |
The request is invalid. The errors map names the field and says what to fix, for example an unknown column, a row that is not an object, or too many rows. |
Manage tables with an AI agent
Agents connected to the MCP server can manage tables with the same abilities.
| Tool | Ability | What it does |
|---|---|---|
list_data_tables |
data-tables:read |
List your tables. |
get_data_table |
data-tables:read |
Show one table with a page of rows. |
create_data_table |
data-tables:write |
Create a table, optionally with first rows. |
update_data_table |
data-tables:write |
Rename a table or change its slug. |
replace_data_table_rows |
data-tables:write |
Replace the whole table in one step. |
upsert_data_table_rows |
data-tables:write |
Update rows by a key column and add the rest. |
delete_data_table |
data-tables:write |
Delete a table (runs in the background). |
refresh_data_table |
data-tables:write |
Fetch an API-linked table again now (up to 6 a minute). |
Example prompt: "Replace the rows of my pallet_rates table with this export, then show me the first five rows." The agent reads the result of each call, so invalid data is reported back instead of half-applied.
