Skip to content

pyquickbase

A typed Python SDK for the Quickbase API, with matching sync and async clients, and policies that limit what a client, or an AI agent, can do.

Get started Try it in your browser

from datetime import date
from pyquickbase import F, Quickbase

with Quickbase(realm="acme", token="your_user_token") as qb:
    tasks = qb.app("bq1234567").table("Tasks")

    overdue = (F("Status") != "Done") & (F("Due Date") < date.today())
    for task in tasks.query(where=overdue, select=["Title", "Due Date"], order_by="-Due Date"):
        print(task.id, task["Title"], task["Due Date"])

    tasks.update([{"Record ID#": 7, "Status": "Done"}])

Why use it

  • Names, not IDs

    Field labels and table names everywhere, with real date and datetime values.

  • Queries that can't silently fail

    F("Status") == "Done" instead of {7.EX.'Done'}, checked before it's sent.

  • Errors that say what happened

    A failed row raises WriteError, listing what was written and what wasn't.

  • Policies

    Limit a client to the tables, fields, and records its job needs.

  • Built for AI agents

    Typed operations for tool calls, results as plain data, and these docs as llms.txt.

The Quickbase REST API accepts many mistakes without complaint. A lowercase operator acts like "contains", an unknown field matches nothing, a failed row sits inside a successful response, and writing null to a field does nothing. This SDK turns those into errors or correct behavior.

With the REST API With pyquickbase
Numeric field IDs everywhere Field labels and table names, or IDs if you prefer
{7.EX.'Done'}AND{9.BF.'today'} (F("Status") == "Done") & (F("Due Date") < date.today())
Broken queries return plausible results Broken queries raise QueryError before sending
Manual skip and top paging for record in table.query(...)
Rows like {"7": {"value": "Done"}} record["Status"], with real date and datetime values
Failed rows inside a successful response WriteError, listing what failed and what was written

See the difference

You import three rows, and one has an invalid status:

rows = [
    {"Title": "Order chairs", "Status": "Open"},
    {"Title": "Book venue", "Status": "Finished"},  # Not a valid status
    {"Title": "Send invites", "Status": "Open"},
]

The REST API saves the other two and returns HTTP 207. That's a success status, so a normal check passes, and the failed row is only listed inside the response body:

response = httpx.post(url, headers=headers, json=body)
response.raise_for_status()  # Passes, because 207 is a success status
print("Import finished")  # But one row wasn't saved

pyquickbase checks the response for you and raises an error that says what happened:

try:
    tasks.insert(rows)
except WriteError as error:
    print("Saved:", error.result.created_ids)
    for failed in error.result.errors:
        print("Failed:", rows[failed.index]["Title"], "-", *failed.messages)
Saved: (25, 26)
Failed: Book venue - The field with ID '7' has an invalid choice.

Try it in the playground, which uses simulated data based on recorded API behavior.

Install

pip install pyquickbase==1.0.0rc13

It needs Python 3.11 or newer. Next, see Getting started.