Writing Data
Add rows to your Google Sheet via the SheetsAPI POST endpoint - request format, required headers, validation, and bulk write patterns.
SheetsAPI supports writing new rows to your Google Sheet via a POST request to the
same endpoint used for reading. Each POST appends one row to the bottom of the sheet.
Endpoint
POST /api/spreadsheets/{userKey}/{sheetName}
Required headers
| Header | Value |
|---|---|
Authorization | Bearer sk_your_api_key_here |
Content-Type | application/json |
Body format
{
"columnName1": "value1",
"columnName2": "value2"
}Keys must match the column headers in your sheet's first row exactly (case-sensitive). Values must be strings. Omitted columns are left empty in that row.
Example - add a product
curl -X POST \
https://sheetsapi.gkit.mreshank.com/api/spreadsheets/YOUR_USER_KEY/Products \
-H "Authorization: Bearer sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"name":"Widget Pro","price":"49.99","category":"Widgets"}'Response
On success, the API returns 201 Created with the row that was appended:
{
"name": "Widget Pro",
"price": "49.99",
"category": "Widgets"
}Field validation
SheetsAPI performs basic validation before writing:
- Unknown columns - keys not present in the header row are silently ignored
- Non-string values - numbers and booleans are coerced to strings
- Missing required fields - the API does not enforce required fields; that is your app's responsibility
- Maximum row size - Google Sheets cells have a 50,000-character limit per cell
JavaScript / TypeScript
async function addProduct(name: string, price: number, category: string) {
const resp = await fetch(
`https://sheetsapi.gkit.mreshank.com/api/spreadsheets/${USER_KEY}/Products`,
{
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ name, price: String(price), category }),
},
);
if (!resp.ok) throw new Error(`Failed: ${resp.status} ${await resp.text()}`);
return resp.json();
}Python
import httpx
def add_row(user_key: str, sheet: str, row: dict, api_key: str) -> dict:
resp = httpx.post(
f"https://sheetsapi.gkit.mreshank.com/api/spreadsheets/{user_key}/{sheet}",
headers={"Authorization": f"Bearer {api_key}"},
json={k: str(v) for k, v in row.items()}
)
resp.raise_for_status()
return resp.json()Bulk writes (sequential loop)
SheetsAPI does not yet support batch POST (multiple rows in one request). For bulk writes, send requests sequentially or with controlled concurrency to avoid hitting the rate limit:
async function bulkWrite(rows: Record<string, string>[], delayMs = 200) {
const results = [];
for (const row of rows) {
const resp = await fetch(URL, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(row),
});
results.push(await resp.json());
await new Promise((r) => setTimeout(r, delayMs)); // pace requests
}
return results;
}A 200 ms delay between writes keeps you well within the default rate limit.
Controlled concurrency
For faster bulk imports, run up to 5 requests in parallel:
import pLimit from "p-limit";
const limit = pLimit(5);
const results = await Promise.all(
rows.map((row) =>
limit(() =>
fetch(URL, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(row),
}).then((r) => r.json()),
),
),
);Idempotency
SheetsAPI does not deduplicate rows automatically. If you retry a failed POST, the row may be written twice. To avoid duplicates:
- Check for an existing row with
GET /api/spreadsheets/{userKey}/{sheet}?search=id:{id}before writing. - Or maintain a write log on your side (database, Redis set) and skip IDs already written.
Error responses
| Status | Meaning |
|---|---|
201 Created | Row appended successfully |
400 Bad Request | Malformed JSON or invalid body |
401 Unauthorized | Missing or invalid API key |
403 Forbidden | Sheet is private and the key lacks write permission |
404 Not Found | Unknown sheet name or user key |
429 Too Many Requests | Rate limit exceeded - see Retry-After header |
500 Internal Server Error | Google Sheets API error |
After writing - invalidate your cache
If you cache GET responses, invalidate the cache immediately after a successful POST:
async function addProductAndInvalidate(row: Record<string, string>) {
await fetch(WRITE_URL, { method: "POST" /* ... */ });
// Clear cached product list
await redis.del("products:list");
}See Caching Strategies for patterns.