API Documentation

Query your Google Sheets data programmatically using the SheetBoy API.

Base URL: https://sheetboy.com

Get Started

1

Sign in with Google

Create an account by signing in with the Google account that has access to your sheets. This stores your credentials securely for API access.

Sign in
2

Create an API key

Go to the Developer page and generate an API key. Save the key securely — it is only shown once.

Developer page
3

Get tokens from admin

Contact the SheetBoy admin to get tokens credited to your account. Every API operation costs tokens (e.g. 1 token per query).

View token costs
4

Import & query via API

Import a Google Sheet (shared with your Google account) via the API, then query it with natural language. See examples below.

View examples

Authentication

All API requests require an API key. Generate one from your Developer page.

Include your API key in the Authorization header:

Authorization: Bearer sw_live_your_api_key_here

Google Sheets access: The API uses your Google credentials (stored when you first sign in) to access sheets. Any Google Sheet shared with your Google account can be imported and queried via the API.

Token Billing

Every API operation costs tokens. Your admin assigns tokens to your account. If you run out, API calls return 402 with your current balance and the required cost.

OperationCost
Import sheet5 tokens per 100 rows (rounded up)
Query1 token
Sync5 tokens
Edit cells2 tokens
Get sheet info / Manage tabsFree (0 tokens)

Check your balance anytime via GET /api/v1/tokens. Token balance and cost are also returned in X-Token-Balance and X-Token-Cost response headers.

Example: Importing a sheet with 250 rows costs ceil(250/100) × 5 = 15 tokens. A sheet with 50 rows costs 5 tokens (minimum).

GET/api/v1/sheets/:id

Get sheet metadata including tab list with numbers and active status. Free (0 tokens).

Success Response 200

json
{
  "sheet_id": "a1b2c3d4-...",
  "name": "Sales Data",
  "row_count": 1500,
  "tab_count": 3,
  "active_tabs": ["Revenue", "Summary"],
  "tabs": [
    { "number": 1, "name": "Revenue", "active": true, "headers": ["Date", "Amount"] },
    { "number": 2, "name": "Summary", "active": true, "headers": ["Region", "Total"] },
    { "number": 3, "name": "Raw", "active": false, "headers": ["ID", "Value"] }
  ],
  "message": "2 of 3 tabs active. Queries use: Revenue, Summary."
}
PATCH/api/v1/sheets/:id

Update which tabs are active for queries. Free (0 tokens). Inactive tabs stay stored but are excluded from queries.

Request Body

json
// By tab name
{ "active_tabs": ["Revenue", "Summary"] }

// By tab number (1-indexed)
{ "active_tabs": [1, 3] }

// Mixed (names and numbers)
{ "active_tabs": ["Revenue", 3] }

// Reset to all tabs active
{ "active_tabs": null }
FieldTypeRequiredDescription
active_tabsarray | nullYesArray of tab names (strings) or numbers (1-indexed), or null to reset all tabs to active

Success Response 200

json
{
  "sheet_id": "a1b2c3d4-...",
  "active_tabs": ["Revenue", "Summary"],
  "tabs": [
    { "number": 1, "name": "Revenue", "active": true },
    { "number": 2, "name": "Summary", "active": true },
    { "number": 3, "name": "Raw", "active": false }
  ],
  "message": "Active tabs updated. Queries will now use: Revenue, Summary."
}

Error Responses

StatusMeaning
400Invalid tab name/number, or empty array (at least 1 tab required)
401Missing or invalid API key
404Sheet not found or access denied

Endpoints

POST/api/v1/query

Run a natural-language question against an imported sheet. Requires API key auth. Only active tabs are included in the query (see PATCH /sheets/:id).

Request Body

json
{
  "sheet_id": "uuid-of-your-sheet",
  "question": "What is the total revenue?"
}
FieldTypeRequiredDescription
sheet_idstringYesUUID of the imported sheet
questionstringYesNatural-language question (max 1,000 characters)

Success Response 200

json
{
  "answer": "The total revenue is $12,50,000.",
  "type": "text",
  "tokens_used": 450,
  "cached": false,
  "cost": 0.005
}

Error Responses

StatusMeaning
401Missing or invalid API key
402Insufficient tokens
404Sheet not found or access denied
429Rate limit exceeded
POST/api/v1/sheets

Import a Google Sheet by URL or upload data directly. Requires API key auth.

Mode 1: Google Sheet URL

Pass a Google Sheets URL to import. The sheet must be shared with your connected Google account.

json
{
  "sheet_url": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms/edit"
}

Mode 2: Direct Data Upload

Upload data directly as an array of objects with explicit headers. Useful for CSV data or non-Google sources.

json
{
  "headers": ["Name", "Revenue", "Region"],
  "data": [
    { "Name": "Product A", "Revenue": 50000, "Region": "US" },
    { "Name": "Product B", "Revenue": 32000, "Region": "EU" },
    { "Name": "Product C", "Revenue": 41000, "Region": "US" }
  ]
}

Success Response 200

json
{
  "sheet_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "Sales Data",
  "status": "ready",
  "row_count": 1500,
  "column_count": 12,
  "tab_count": 3,
  "active_tabs": null,
  "tabs": [
    { "number": 1, "name": "Revenue", "row_count": 500, "headers": ["Date", "Amount"] },
    { "number": 2, "name": "Summary", "row_count": 200, "headers": ["Region", "Total"] },
    { "number": 3, "name": "Raw", "row_count": 800, "headers": ["ID", "Value"] }
  ],
  "message": "Sheet imported with 3 tabs. All tabs are active by default. ..."
}

Use the returned sheet_id in subsequent /api/v1/query calls. If the same Google Sheet URL was already imported, the existing sheet ID is returned. Each tab includes a number (1-indexed) for easy reference. By default, all tabs are active (active_tabs: null). Use PATCH /api/v1/sheets/:id to select specific tabs.

Error Responses

StatusMeaning
401Missing or invalid API key
400Invalid body -- must provide either sheet_url or data + headers
POST/api/v1/sheets/:id/sync

Re-fetch the latest data from Google Sheets. Costs 5 tokens per sync.

Success Response 200

json
{
  "sheet_id": "a1b2c3d4-...",
  "name": "Sales Data",
  "status": "synced",
  "row_count": 1500,
  "column_count": 12,
  "tab_count": 3,
  "last_synced_at": "2026-02-13T10:00:00Z"
}
POST/api/v1/edit

Write cell updates back to a Google Sheet. Costs 2 tokens. Max 100 cells per request. The sheet must be shared with edit (write) permission.

Request Body

json
{
  "sheet_id": "uuid-of-your-sheet",
  "edits": [
    { "cell": "A1", "value": "Updated Name" },
    { "cell": "B2", "value": 42000 },
    { "cell": "C3", "value": "=SUM(B1:B2)" }
  ],
  "tab": "Sheet1"
}
FieldTypeRequiredDescription
sheet_idstringYesUUID of the imported sheet
editsarrayYesArray of {cell, value} objects. Cell uses A1 notation.
tabstringNoTab name (defaults to first tab)

Success Response 200

json
{
  "success": true,
  "cells_updated": 3
}
GET/api/v1/tokens

Check your current token balance and recent transaction history.

Response 200

json
{
  "balance": 485,
  "costs": { "import": 5, "query": 1, "sync": 5, "edit": 2 },
  "history": [
    {
      "amount": -1,
      "balance_after": 485,
      "operation": "query",
      "description": "API query",
      "created_at": "2026-02-13T09:30:00Z"
    }
  ]
}

API Key Management

Note: The keys endpoints use session authentication (browser cookies), not API key auth. These are meant to be called from your logged-in browser session or with your session cookie.

POST/api/v1/keys

Create a new API key. The raw key is only returned once.

Request Body

json
{
  "name": "My Bot Key"
}

Response 200

json
{
  "key": "sw_live_abc123def456...",
  "id": "key-uuid",
  "name": "My Bot Key"
}

Save the key immediately. It will not be shown again.

GET/api/v1/keys

List all API keys for the authenticated user.

Response 200

json
{
  "keys": [
    {
      "id": "key-uuid",
      "name": "My Bot Key",
      "key_prefix": "sw_live_abc1...",
      "is_active": true,
      "last_used_at": "2025-06-15T10:30:00Z",
      "created_at": "2025-06-01T08:00:00Z"
    }
  ]
}
DELETE/api/v1/keys

Revoke an API key. The key will immediately stop working.

Request Body

json
{
  "key_id": "key-uuid-to-revoke"
}

Response 200

json
{
  "success": true
}

Code Examples

cURL

bash
curl -X POST https://sheetboy.com/api/v1/query \
  -H "Authorization: Bearer sw_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "sheet_id": "your-sheet-id",
    "question": "Total sales last month?"
  }'

JavaScript / Node.js

javascript
const response = await fetch("https://sheetboy.com/api/v1/query", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sw_live_your_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    sheet_id: "your-sheet-id",
    question: "What are the top 5 products by revenue?",
  }),
});

const data = await response.json();
console.log(data.answer);

Python

python
import requests

response = requests.post(
    "https://sheetboy.com/api/v1/query",
    headers={
        "Authorization": "Bearer sw_live_your_key",
        "Content-Type": "application/json",
    },
    json={
        "sheet_id": "your-sheet-id",
        "question": "What are the top 5 products by revenue?",
    },
)

data = response.json()
print(data["answer"])

Import a Sheet via API (cURL)

bash
# Import from Google Sheets URL
curl -X POST https://sheetboy.com/api/v1/sheets \
  -H "Authorization: Bearer sw_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "sheet_url": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms/edit"
  }'

# Upload data directly
curl -X POST https://sheetboy.com/api/v1/sheets \
  -H "Authorization: Bearer sw_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "headers": ["Name", "Revenue"],
    "data": [
      {"Name": "Product A", "Revenue": 50000},
      {"Name": "Product B", "Revenue": 32000}
    ]
  }'

Managing Tabs

bash
# Get sheet info with tab list
curl https://sheetboy.com/api/v1/sheets/YOUR_SHEET_ID \
  -H "Authorization: Bearer sw_live_your_key"

# Activate only tabs 1 and 3
curl -X PATCH https://sheetboy.com/api/v1/sheets/YOUR_SHEET_ID \
  -H "Authorization: Bearer sw_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "active_tabs": [1, 3] }'

# Activate by name
curl -X PATCH https://sheetboy.com/api/v1/sheets/YOUR_SHEET_ID \
  -H "Authorization: Bearer sw_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "active_tabs": ["Revenue", "Summary"] }'

# Reset to all tabs active
curl -X PATCH https://sheetboy.com/api/v1/sheets/YOUR_SHEET_ID \
  -H "Authorization: Bearer sw_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "active_tabs": null }'

Full Workflow (Python)

python
import requests

API_KEY = "sw_live_your_key"
BASE = "https://sheetboy.com/api/v1"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

# Step 1: Import a sheet
import_resp = requests.post(
    f"{BASE}/sheets",
    headers=HEADERS,
    json={
        "sheet_url": "https://docs.google.com/spreadsheets/d/YOUR_ID/edit"
    },
)
sheet_id = import_resp.json()["sheet_id"]
print(f"Imported sheet: {sheet_id}")

# Step 2: Query the sheet
query_resp = requests.post(
    f"{BASE}/query",
    headers=HEADERS,
    json={
        "sheet_id": sheet_id,
        "question": "What are the total sales by region?",
    },
)
print(query_resp.json()["answer"])

Getting Your Sheet ID

After importing a sheet in the SheetBoy dashboard, you can find the sheet ID in two places:

  • The URL when viewing a sheet: sheetboy.com/sheets/[id]
  • The sheet details card on your dashboard
  • The response from POST /api/v1/sheets when importing via the API

Tip: The sheet ID is a UUID like a1b2c3d4-e5f6-7890-abcd-ef1234567890. It is different from the Google Spreadsheet ID in the original URL.

Need Help?

If you have questions about the API, reach out to us at support@sheetboy.com