PasteSheet icon PasteSheet logo mark — a spreadsheet grid with a curly brace on a green rounded square PasteSheet

Use Google Sheets as a REST API

A Google Sheet makes a surprisingly good backing store for content, config, and reference data. PasteSheet puts a real REST API in front of it — typed JSON, query parameters, caching, and access control — so your app can just fetch it.

Last updated

Key facts

  • Google's Sheets API is cell-oriented: it reads ranges like A1:D50, not records. Reassembling those into row objects is work you do yourself. source
  • Google's API requires a Google Cloud project plus OAuth credentials or a service account before it will return a single row. source
  • The Google Sheets API allows 300 read requests per minute per project and 60 per minute per user. Past that it returns 429 RESOURCE_EXHAUSTED. source
  • A cached endpoint reads the sheet once per TTL, not once per request — so 10,000 visitors become one upstream read, and Google's quota stops being your problem.
  • Free tiers among hosted sheet-to-API services vary widely — SheetDB offers 2 APIs and 500 requests a month free, while Sheet.best offers a 30-day trial and no permanently free tier. PasteSheet's Free plan is 3 endpoints and 2,000 requests a month, with MCP included. Vendor limits verified 22 July 2026. source

How do you turn a Google Sheet into a REST API?

Paste a link-shared sheet URL into PasteSheet, or connect Google and choose a restricted sheet in Picker. Either path publishes the rows at a JSON endpoint you can GET immediately. There is no Google Cloud project for you to create, and every edit shows up through the API once the cache refreshes.

There are really only three ways to do this. You can call Google's own Sheets API, which is cell-oriented — it reads ranges like A1:D50 and leaves you to reassemble them into records, after you have stood up a Cloud project and OAuth credentials. You can publish an Apps Script web app, which means writing and maintaining a script, and living inside Apps Script's execution quotas. Or you can point a hosted service at the sheet and get an endpoint. This page is about the third path, and about what to check before you pick one.

PasteSheet returns records: one JSON object per row, with your column names as keys and types already applied. No range maths, no header-row bookkeeping, no SDK.

You can see the exact payload without signing up: the free Google Sheets to JSON converter runs the same conversion in your browser. The difference is that a converter hands you a file, and an endpoint hands you a URL that never goes stale.

From sheet to live endpoint

The whole conversion is four steps and takes about a minute:

  1. 1 Give the sheet a header row — those cells become your JSON keys, so name them the way you want your API to read.
  2. 2 Choose your source path. For a public source, set sharing to Anyone with the link → Viewer. For a restricted source, connect your Google account and select the exact sheet in Google Picker.
  3. 3 Paste the public URL, or finish the Picker flow. PasteSheet reads the tabs, previews the rows, and infers each column's type.
  4. 4 Save. You now have a permanent URL like https://pastesheet.com/api/your-endpoint-id that any app, site, or AI agent can read.

The endpoint

Every connected sheet gets a JSON endpoint. A GET request returns rows plus pagination metadata:

terminal
curl 'https://pastesheet.com/api/your-endpoint-id?limit=2'

{
  "data": [
    { "id": 1, "name": "Blue Widget", "price": 19.99, "in_stock": true },
    { "id": 2, "name": "Red Widget",  "price": 24.5,  "in_stock": false }
  ],
  "total": 128,
  "limit": 2,
  "offset": 0,
  "meta": { "row_cap": 500, "row_cap_applied": false }
}

What the response tells you

total is the match count before pagination, so a client always knows how much data exists beyond the window it received. meta.row_cap_applied is the honest part: if your plan's row cap trimmed the result, the response says so instead of quietly reading short. That single flag is the difference between a paginated list that is correct and one that silently loses its tail.

A multi-tab sheet addresses each tab as its own path segment — /api/your-endpoint-id/Products — so one spreadsheet can back several resources.

Query without a query language

Every column is queryable with plain URL parameters. There is no DSL to learn and nothing to escape:

  • ?status=active — exact-match filter on any column.
  • ?contains[name]=jo — partial match on a named column.
  • ?search=widget — full-text search across every column.
  • ?sort=created&order=desc — sort by any field.
  • ?limit=20&offset=40 — page through results.
  • ?group_by=category&count=1 — group rows and count them server-side.
  • ?group_by=category&sum=revenue&avg=price — totals and averages, computed before the response leaves us.

The aggregation parameters matter more than they look. Without them, "what is the total revenue per category?" means downloading every row and doing the arithmetic in your client — on every page load, in every language you support. With them, the client receives the answer. Full-text search and aggregation are Pro-plan features; filtering, sorting, and pagination work on every plan including Free.

Read it from JavaScript

It is plain JSON over HTTP with CORS enabled, so browser code can fetch it directly — no proxy, no SDK, no key for a public endpoint:

app.js
const res = await fetch(
  'https://pastesheet.com/api/your-endpoint-id?status=active&sort=created&order=desc&limit=20'
);
const { data, total } = await res.json();

data.forEach(row => console.log(row.name, row.price));

Read it from Python

Nothing Google-specific — requests and the standard library are enough:

main.py
import requests

res = requests.get(
    "https://pastesheet.com/api/your-endpoint-id",
    params={"status": "active", "limit": 20},
)
rows = res.json()["data"]

for row in rows:
    print(row["name"], row["price"])

Read it from PHP

A private endpoint takes a bearer key in the Authorization header; a public one needs no header at all:

app.php
$response = Http::withToken('ps_your_api_key')
    ->get('https://pastesheet.com/api/your-endpoint-id', [
        'status' => 'active',
        'limit' => 20,
    ]);

foreach ($response->json('data') as $row) {
    echo $row['name'].' — '.$row['price'].PHP_EOL;
}

Aggregate from the command line

Grouped totals come back already computed, so a dashboard can call one URL instead of paging through the sheet:

terminal
curl 'https://pastesheet.com/api/your-endpoint-id?group_by=category&count=1&sum=revenue'

{
  "data": [
    { "category": "Widgets", "count": 62, "revenue": 12480.5 },
    { "category": "Gadgets", "count": 41, "revenue":  8310.0 }
  ],
  "total": 2
}

The four ways to do this, compared

The trade-offs are not subtle, and they are mostly about setup cost and what the API is allowed to do to your spreadsheet:

PasteSheet Google Sheets API Apps Script web app Typical sheet-to-API SaaS
Setup Paste a share URL Cloud project + OAuth or service account Write, deploy & maintain a script Connect a Google account
Returns Typed row objects Cells and ranges Whatever you code Row objects
Access model Read-only by design Whatever you scope Whatever you code Usually read-write CRUD
Caching Built in, TTL you set None — you build it None — you build it Varies
Rate limits Per-plan, cache absorbs traffic 60 reads/min per user Apps Script quotas Per-plan request cap
Filter, sort, paginate URL parameters You implement it You implement it Usually yes
Server-side aggregation group_by, count, sum, avg No You implement it Rare
Schema-drift protection Snapshot, lock & alerts No No No
Also an MCP server Yes — same endpoint No No No
Free tier 3 endpoints, 2,000 req/mo Free within quota Free within quota Varies — some are trial-only

What happens when the traffic arrives

This is the part almost nobody writes about, and it is where sheet-backed APIs actually break. Google's Sheets API allows 300 read requests per minute per project and 60 per minute per user; past that it returns 429 RESOURCE_EXHAUSTED. If your API reads the spreadsheet once per incoming request, a modest traffic spike — a launch, a newsletter, a scraper — takes the whole thing down.

A cache is the entire answer. PasteSheet reads the sheet once per TTL, not once per request, so 10,000 visitors in five minutes become a single upstream read and Google's quota stops being your problem. The TTL is 5 minutes on Free and tunable from 30 seconds to 1 hour on paid plans, and you can force a refresh when you want an edit live immediately.

The deep dives: Google Sheets API rate limits, fixing 429 quota-exceeded errors, and how to cache a Google Sheets JSON API.

Read-only, on purpose

Most "sheet to API" tools lead with read-write CRUD, and treat that as the headline feature. It is worth asking what it costs. Read-write means a third party holds edit access to your spreadsheet, and it means any credential that leaks — in a client bundle, a repo, a screenshot, a chat log — can rewrite or wipe your data rather than merely read it.

PasteSheet is deliberately read-only: it publishes the rows, and nothing can change the sheet through the API. That is what makes an endpoint safe to embed in a public page, ship inside a mobile app, or hand to an AI agent that you do not fully control. A public sheet needs no API key at all, because there is nothing a key would protect.

If you genuinely need writes, a sheet is usually the wrong database — see is Google Sheets good as a database? for where the line sits. Otherwise, read the same endpoint from React, Python, or Laravel.

What happens when someone renames a column

A spreadsheet is a shared document, which means the schema of your API is editable by anyone with access to it. Someone renames Price to Unit Price, and every consumer that reads row.price starts returning undefined — with a 200 OK, so nothing alerts and nothing fails loudly.

PasteSheet snapshots the column schema on every read and compares it against the last known shape. You can lock an endpoint's schema, so a drifting sheet returns a clear 409 instead of silently serving the wrong payload, and you can have drift alerts sent by email or webhook. It is the failure mode that quietly breaks sheet-backed apps, and no other approach on the table above addresses it.

The same endpoint is also an MCP server

Once a sheet is a REST API, the interesting next question is whether an AI agent can read it too. It can: every PasteSheet endpoint is simultaneously a Model Context Protocol server, exposing list_tabs, get_schema and query_rows to Claude, ChatGPT, Cursor, and anything else that speaks MCP.

It runs on the same query engine as the REST endpoint, so an agent and your application see identical rows, with identical types, filtered identically — and the read-only guarantee above is exactly why handing that connection to a model is safe. MCP is included on the Free plan for public endpoints.

Typed, cached, and access-controlled

Column types and aliases are inferred automatically, so numbers, booleans, and dates come back typed rather than as raw strings, and a column called Order Date can be exposed as order_date without touching the spreadsheet. Responses are cached at the edge with a Cache-Control header your CDN and browser will honour, and any endpoint can be locked behind a bearer key.

Prefer to walk through converting a sheet step by step, or see what a sheet-backed API is actually good for in the use-case library.

What it costs

You do not need a paid plan to get a working endpoint:

Free

For side projects and trying things out.

$0 /mo
Endpoints
3
Requests / mo
2,000
Row cap
500
  • MCP for AI agents
  • Private endpoints & keys
  • Full-text search
  • Count, sum, avg & group by

The Free plan covers 3 endpoints and 2,000 requests a month with a 500-row cap, MCP included — no credit card and no expiry. Paid plans start at Starter ($9/mo) and add private endpoints with bearer keys, a tunable cache TTL, more tabs, and a higher row cap; full-text search and aggregation arrive on Pro.

Worth knowing when you compare: some hosted sheet-to-API services have no permanently free tier at all, only a trial. The numbers on the cards here are the real limits, read straight from our plan configuration.

Frequently asked questions

Does Google Sheets have a REST API?

Google offers the Sheets API, but it is cell-oriented and needs OAuth and code. PasteSheet gives you a row-oriented JSON REST API from a pasted URL, with no setup.

Do I need a Google Cloud project?

Not your own. Public sources need a share URL. Restricted sources use PasteSheet's Google connection and Picker flow, while Google's own Sheets API still requires a Cloud project plus credentials before it returns a row.

Do I need a Google Sheets API key?

No. PasteSheet reads published and link-shared sheets, so a public endpoint is keyless. The optional bearer key protects your endpoint, not your Google account.

What format does the API return?

JSON shaped as { data, total, limit, offset, meta }, where each row is an object keyed by your column aliases with values cast to their inferred types. total is the match count before pagination.

Can I filter and sort in the URL?

Yes — exact-match filters, contains matches, full-text search, sort/order, and limit/offset are all plain query parameters. No query language to learn.

Can the API write back to my sheet?

No, and that is deliberate. PasteSheet is read-only by design, so an endpoint is safe to embed in a public page or hand to an AI agent — it can query every row but change none.

How is this different from an Apps Script web app?

An Apps Script web app is code you write, deploy, and maintain, running inside Apps Script execution quotas. PasteSheet is a hosted endpoint with caching, typed columns, and query parameters already built.

What happens if my endpoint gets a lot of traffic?

Responses are served from cache, so the sheet is read once per TTL rather than once per request. That keeps you clear of Google's 60-reads-per-minute-per-user limit even under a spike.

Does my sheet have to be link-shared?

No. A public source can use Anyone with the link → Viewer. For a restricted source, connect your Google account and choose the exact sheet in Picker. The endpoint can separately be public or protected by a bearer key.

Can I read it from the browser?

Yes. Responses are CORS-enabled, so front-end code can fetch them directly without a proxy or a server-side shim.

What if someone renames a column?

You can lock an endpoint's schema so a drifting sheet returns a clear 409 instead of silently serving the wrong shape, and have drift alerts sent by email or webhook.

Is it free?

The Free plan covers 3 endpoints and 2,000 requests a month with MCP included, no credit card and no expiry. Paid plans start at $9/mo for private endpoints, a tunable cache TTL, and higher limits.

Sources

Related guides

Turn your sheet into an API in minutes

Paste a Google Sheet URL and get a live REST API and MCP server — no backend, no code, free to start.