Dataville Connected sheets API

Connect a Google Sheet and query it alongside the public datasets.

Operations 2

POST /api/v1/datasets/{id}/query Run SQL against one connected sheet #
GET /api/v1/datasets/{id}/search Keyword-search a connected sheet #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/dataville-com:dataville-com-connected-sheets-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

dataville-com-connected-sheets-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Dataville Connected sheets API
  version: 1.0.0
  description: 'Dataville is a unified data API: a single REST surface over Wikipedia, arXiv,

    Project Gutenberg, the US Census, USDA FoodData, Papers with Code, SEC EDGAR,

    OpenAlex, PyPI and Stack Exchange — plus bulk CSV/Parquet/DuckDB export, a

    SQL endpoint, and "bring your own data" Google Sheets connections.


    ## Authentication


    Data, export and query endpoints never hard-reject at the middleware level — an

    unauthenticated caller simply gets the anonymous tier (50 requests per day per

    IP).


    ### API key


    ```

    Authorization: Bearer dataville_xxxxxxxxxxxxxxxx

    ```


    Create and manage keys from the **API Keys** page in the

    Dataville dashboard. Keys start with `dataville_`

    (legacy keys start with `datax_`). For clients that cannot set headers — DuckDB

    WASM, the DuckDB CLI''s `httpfs` reader — the same key may be passed as the

    `?token=` query parameter.


    The Dataville web app authenticates with its own session tokens; those routes

    are internal and not part of the public API surface.


    ## Credits and metering


    Authenticated usage is metered against a monthly **Dataville credit** balance in

    USD, shared across an account''s sessions and API keys. Each tier is granted

    credit every month — Free **$5**, Developer **$29**, Pro **$99** — and each

    query deducts a per-source, per-tier amount:


    | Class | Free | Developer | Pro |

    | --- | --- | --- | --- |

    | Open/public datasets | $0.0050 | $0.0050 | $0.0040 |

    | Wikipedia (premium) | $0.0250 | $0.0150 | $0.0125 |


    A `POST /api/v1/query` call is charged per row returned. When the balance

    reaches zero the API returns **402 Payment Required** until the monthly reset,

    a plan upgrade, or a credit top-off. Every metered response carries:


    - `X-Credits-Remaining` — remaining balance, USD

    - `X-Credit-Cost` — amount charged for this request, USD


    Check your request quota any time via `GET /api/v1/auth/usage`; your credit

    balance is reported on every metered response in `X-Credits-Remaining` and on

    the dashboard''s **Billing** page.


    ## Rate limiting


    Anonymous callers are limited by IP (50 requests per 24 hours) and receive

    **429** when they exceed it, with `X-RateLimit-Limit`, `X-RateLimit-Remaining`

    and `X-RateLimit-Reset` headers. Authenticated callers are governed by credits

    rather than a request count. Export and SQL routes carry their own stricter

    limit (1,000 per day per account), as does support submission (5 per hour).


    Every route also shares a burst limit of 100 requests per 15 minutes per IP,

    checked before authentication. It answers **429** with `data.code:

    RATE_LIMITED`, `RateLimit-*` headers and `Retry-After`. The anonymous daily

    limit answers with `data.code: REQUEST_LIMIT_EXCEEDED`. Branch on the code:

    the first clears in minutes; the second needs an API key or the daily reset.


    ## Errors


    Every error body carries a human-readable `error`/`message` string that is safe

    to show a user verbatim, and data-source errors additionally carry a stable

    `data.code` (`UPSTREAM_RATE_LIMITED`, `UPSTREAM_UNAVAILABLE`,

    `UPSTREAM_FORBIDDEN`, `UPSTREAM_BAD_RESPONSE`, `SOURCE_UNAVAILABLE`,

    `INTERNAL_ERROR`) that clients should branch on instead of parsing prose. When

    an upstream tells us how long to wait, the response sets `Retry-After`.

    Rate-limit 429s carry a code too (`RATE_LIMITED`, `REQUEST_LIMIT_EXCEEDED`;

    see Rate limiting).


    ## Stale results


    A live source that is down is answered from Dataville''s own stored copy where

    one exists. Those responses include a `data.stale` object naming the source and

    when the copy was taken — the answer is real, but may be out of date.'
  contact:
    name: Dataville Support
    email: support@dataville.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
servers:
- url: https://api.dataville.com
  description: Production
security:
- ApiKeyAuth: []
tags:
- name: Connected sheets
  description: Connect a Google Sheet and query it alongside the public datasets.
paths:
  /api/v1/datasets/{id}/query:
    post:
      tags:
      - Connected sheets
      operationId: queryDataset
      summary: Run SQL against one connected sheet
      description: 'A SELECT-only sandbox scoped to a single dataset. Reference the sheet as

        `sheet_data` in the SQL. Accepts an API key as well as a Clerk session, so

        connected data is queryable programmatically.


        ```bash

        curl -X POST https://api.dataville.com/api/v1/datasets/my-budget-2026/query \

        -H "Authorization: Bearer $DATAVILLE_API_KEY" \

        -H "Content-Type: application/json" \

        -d ''{"sql":"SELECT category, SUM(amount) FROM sheet_data GROUP BY 1"}''

        ```'
      parameters:
      - $ref: '#/components/parameters/DatasetId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - sql
              properties:
                sql:
                  type: string
                  maxLength: 10000
                  example: SELECT * FROM sheet_data LIMIT 10
      responses:
        '200':
          description: Query results.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  row_count:
                    type: integer
                  rows:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                  sql_executed:
                    type: string
        '400':
          description: Invalid SQL, or the dataset is not in a queryable state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimpleError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/DatasetNotFound'
        '408':
          description: Query exceeded the 30-second limit.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimpleError'
  /api/v1/datasets/{id}/search:
    get:
      tags:
      - Connected sheets
      operationId: searchDataset
      summary: Keyword-search a connected sheet
      description: Search every column of a connected sheet without writing SQL. Accepts an API key.
      parameters:
      - $ref: '#/components/parameters/DatasetId'
      - name: q
        in: query
        required: true
        description: Search text (max 500 characters).
        schema:
          type: string
          maxLength: 500
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
      responses:
        '200':
          description: Matching rows.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  row_count:
                    type: integer
                  rows:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '400':
          description: '`q` is missing or too long, or the dataset is not ready.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimpleError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/DatasetNotFound'
components:
  parameters:
    DatasetId:
      name: id
      in: path
      required: true
      description: The dataset's UUID or its friendly slug (e.g. `my-budget-2026`).
      schema:
        type: string
  schemas:
    SimpleError:
      type: object
      properties:
        status:
          type: string
          enum:
          - error
        message:
          type: string
    AuthError:
      type: object
      properties:
        error:
          type: string
        message:
          type: string
  responses:
    DatasetNotFound:
      description: No such dataset for this account.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SimpleError'
          example:
            status: error
            message: Dataset not found.
    Unauthorized:
      description: Authentication required, or the token is invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AuthError'
          example:
            error: Unauthorized
            message: No token provided
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      description: 'A Dataville API key, sent as `Authorization: Bearer dataville_...`. Clients

        that cannot set headers may pass the same key as `?token=`.

        '