Skip to main content
v2026.11,610 entries · CC-BY 4.0

Using the Zotero Web API: Keys, Endpoints, and a Worked Example

How to create a scoped Zotero API key, the user/group/collection/item endpoint structure, and a worked Python example that pages through a collection’s items for a reporting integration.

Ask about Using the Zotero Web API: Keys, Endpoints, and a Worked Example

Answers are drawn from this guide and the rest of the CASRAI corpus, with a link to every source.

Answers are AI-generated from CASRAI’s own published pages and can be wrong, so check the linked sources before relying on one; your question is logged without personal data — never sold, never used to train a third-party model — to show us what CASRAI is missing, so please do not type personal or confidential details. How we use this

Written and maintained by CASRAI Editorial Board

Last updated

Zotero’s own connector and the desktop app cover the day-to-day work of collecting and citing sources. The Zotero Web API is a separate surface entirely: a REST API that lets a script, a reporting tool, or a departmental dashboard read (and, with a suitably scoped key, write) a library’s collections and items directly — without opening Zotero at all. That is the useful case for a research office: pulling a lab’s or a group’s Zotero library into a publication-list report, an institutional repository feed, or a compliance audit, on a schedule, unattended.

This page covers the three things you actually need to get a working request out the door: creating a properly scoped API key, the URL structure the API uses for libraries, collections, and items, and a worked example that pulls every item out of one collection. Endpoint paths, header names, and parameter names below are quoted directly from Zotero’s own Web API v3 documentation, current as of 26 August 2026.

Step 1: Create a scoped API key

API keys are created and managed from your Zotero account settings, at zotero.org/settings/keys/new — not inside the desktop app. The same page that creates the key also displays your account’s numeric user ID, which you’ll need for every request path below.

The key-creation form lets you scope access before you ever use the key: to your personal library only, to one or more specific group libraries, or to all groups you belong to, and independently to read-only or read/write permission. For a reporting integration — a script that only ever needs to pull items out, on a schedule, for a dashboard or a compliance report — create a key scoped to read-only access on only the specific library it needs. A leaked read-only key scoped to one group library can, at worst, expose that library’s metadata; a leaked unscoped read/write key can alter or delete every library it touches. This is the practical version of the “API-key scoping for institutional access” question a research office asks before wiring a Zotero group library into anything automated.

Step 2: Find your library ID

Every request path starts with which library you’re addressing:

  • A personal library uses your numeric user ID: /users/<userID>. The ID is shown on the same API Keys settings page referenced above.
  • A group library uses the group’s numeric ID: /groups/<groupID>. It appears in the group’s own URL on zotero.org (for example, zotero.org/groups/<groupID>/<group-name>) and on the group’s library settings page.

Zotero’s documentation calls this the <userOrGroupPrefix> in every endpoint below. Pulling from a lab’s shared group library — rather than one researcher’s personal library — is almost always the right choice for an institutional reporting integration, since group membership can change without the API key itself needing to be reissued.

Step 3: The endpoint structure — collections and items

Everything under a library is reached through <userOrGroupPrefix>/collections and <userOrGroupPrefix>/items, plus a small number of documented variants:

Endpoint Returns
<prefix>/collections All collections in the library
<prefix>/collections/top Only top-level collections
<prefix>/collections/<collectionKey> One specific collection
<prefix>/collections/<collectionKey>/collections That collection’s subcollections
<prefix>/items All items in the library, excluding the trash
<prefix>/items/top Only top-level items (no standalone notes/attachments)
<prefix>/items/trash Items in the trash
<prefix>/items/<itemKey> One specific item
<prefix>/items/<itemKey>/children That item’s attachments and notes
<prefix>/collections/<collectionKey>/items Every item in one collection — the endpoint the worked example below uses
<prefix>/collections/<collectionKey>/items/top Only top-level items in one collection
<prefix>/publications/items A user’s “My Publications” items

Authentication, versioning, and response format

Zotero’s documentation gives three ways to send the key with a request, in order of preference:

  1. Zotero-API-Key: <your key> as an HTTP header (Zotero’s own preferred form).
  2. Authorization: Bearer <your key> as an HTTP header (the standard OAuth-style bearer form, useful if your HTTP client already has bearer-auth support built in).
  3. ?key=<your key> as a URL query parameter — documented, but not recommended, since a key in the URL ends up in server logs, browser history, and any proxy sitting in between.

Pin the API version with the Zotero-API-Version header (or ?v=3) so a future default-version change on Zotero’s end doesn’t silently alter your response shape. Version 3 is the current default. Set format=json for a script (this is also the default if you don’t set an Accept header requesting Atom); other documented values include atom, bib (a rendered bibliography), keys (a bare newline-separated list of object keys), versions, and a set of export formats — bibtex, biblatex, csljson, csv, mods, ris, and tei among them. For RIS/BibTeX interchange mechanics beyond the API itself, see CASRAI’s RIS file format reference and getting clean BibTeX from a DOI.

Pagination and rate limits

limit controls page size — it defaults to 25 and caps at 100 for the Web API. start is the zero-indexed offset of the first result you want, defaulting to 0. Every response carries a Total-Results header with the full match count, which is what you loop against to know when to stop paging.

Two distinct rate-limit signals are documented, and they mean different things:

  • A Backoff: <seconds> response header is a soft warning — the request still succeeded, but Zotero is asking you to slow down before the next one.
  • A 429 Too Many Requests status, accompanied by a Retry-After: <seconds> header, is a hard stop — the request was rejected. A script pulling a whole library on a schedule should read and respect both headers rather than retrying on a fixed timer.

Worked example: pulling a collection’s items into a script

This pulls every item out of one collection, paging through the full result set. Replace the placeholder user ID, collection key, and key value with your own — the collection key is visible in the collection’s URL inside the Zotero web library or desktop app.

import requests  API_KEY = "your-read-only-scoped-key" USER_ID = "1234567" COLLECTION_KEY = "ABCD1234" BASE = f"https://api.zotero.org/users/{USER_ID}/collections/{COLLECTION_KEY}/items"  headers = {     "Zotero-API-Key": API_KEY,     "Zotero-API-Version": "3", }  items = [] start = 0 limit = 100  while True:     resp = requests.get(         BASE,         headers=headers,         params={"format": "json", "limit": limit, "start": start},     )     resp.raise_for_status()     batch = resp.json()     if not batch:         break     items.extend(batch)      total = int(resp.headers.get("Total-Results", len(items)))     start += limit     if start >= total:         break  print(f"Pulled {len(items)} items from collection {COLLECTION_KEY}") 

Each object in items is a full item record — data.title, data.creators, data.date, data.DOI where present, plus Zotero’s own key and version fields for that item. That’s the shape a reporting script maps into a publication-list report, an institutional repository feed, or whatever the downstream system expects — the API gives you the structured library data; the mapping into your own report format is the remaining, institution-specific work.

The same pagination loop works unchanged against <prefix>/items for a whole library instead of one collection, or against <prefix>/collections/<collectionKey>/items/top if you only want top-level items and not child notes/attachments mixed into the result set.

Frequently asked questions

How do I get a Zotero API key?

Create one at zotero.org/settings/keys/new while signed in to your Zotero account. Scope it to the specific library (or libraries) and the read-only or read/write permission level the integration actually needs, rather than granting broad access by default.

What’s the difference between a user ID and a group ID in the API?

A user ID addresses one person’s personal library (/users/<userID>); a group ID addresses a shared group library (/groups/<groupID>). For an institutional reporting integration built around a lab or department’s shared collection, the group ID is almost always the right one to use, not any individual’s user ID.

Can I write to a Zotero library through the API, not just read from it?

Yes — a key with read/write permission can create, update, and delete items and collections through the same endpoints using PUT/POST/DELETE requests. That mechanism, including how Zotero prevents one client from silently overwriting another’s concurrent edit, is covered separately in the Write Requests section of Zotero’s own API documentation; a reporting integration that only ever reads data doesn’t need it and shouldn’t be issued a write-capable key.

How many items can I retrieve in a single request?

limit caps at 100 per request regardless of what you set it to. Anything larger than that requires paging with start, as in the worked example above.

What happens if I exceed the API’s rate limit?

A soft Backoff header asks you to slow down without failing the request; a hard 429 Too Many Requests response with a Retry-After header means the request itself was rejected and should be retried only after the stated number of seconds.

Related CASRAI reading

For the desktop-app side of Zotero — installing the connector, the Word/LibreOffice plugin, and sync — see Zotero Setup and Troubleshooting and the broader Zotero for Researchers guide. For how Zotero compares to the other major reference managers a research office is likely to support, see Zotero, EndNote, Mendeley, RefWorks & Paperpile compared. If your reporting workflow needs bibliographic data from other sources alongside a Zotero library, CASRAI also covers the PubMed E-utilities API and the Semantic Scholar Academic Graph API, both built to the same documented-vs-measured discipline as this page.

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →

Regulatory Radar

Stop finding out after the fact

$29/month, cancel anytime. Daily digest updates from our analysis, a dashboard holding the same items, and a cited assistant for everything they raise.

  • Federal Register, Federal Register+, Grants.gov, Regulations.gov, NSF News, UKRI, plus CASRAI’s own published content.
  • 44,322 indexed passages, and every answer cites the ones it drew on.