Zotero Server Write API#

This is version 1 of the Zotero Web API. For new development, use API version 3.

This page documents the write methods of the Zotero Web API. See the Read API page for basic information on accessing the API, including possible HTTP status codes not listed here.

An API key with write access to a given library is necessary to use write methods.

To-do:

  • Mappings caching (If-Modified-Since)
  • Non-English type/field locales

Item Type/Field Requests#

For an API client to present an editing UI to its users, it must know what combinations of Zotero item types, fields, and creator types are valid. Clients can request this data from the Zotero API.

As schema changes are currently rare, clients should cache type/field data for a period of time (e.g., one hour) without making further requests. Subsequent requests for new data should then include If-Modified-Since headers containing the contents of the Last-Modified header from the original response. If no changes have occurred, the server will return a 304 Not Modified and clients should continue to use cached data for the same period of time.

User-friendly type/field names will be returned in English by default. Clients can request names in other languages by passing a locale parameter (e.g., GET /itemTypes?locale=fr-FR).

Hint: For manual viewing, add pprint=1 to the following requests for easier-to-read output.

Get All Item Types#

GET /itemTypes
If-Modified-Since: Mon, 14 Mar 2011 22:30:17 GMT
[
  { "itemType" : "book", "localized" : "Book" },
  { "itemType" : "note", "localized" : "Note" },
  ()
]
Common responses
200 OK
304 Not ModifiedNo changes have occurred since If-Modified-Since time.
400 Bad RequestLocale not supported.

Get All Item Fields#

GET /itemFields
If-Modified-Since: Mon, 14 Mar 2011 22:30:17 GMT
[
  { "field" : "title", "localized" : "Title" },
  { "field" : "url", "localized" : "URL" },
  ()
]
Common responses
200 OK
304 Not ModifiedNo changes have occurred since If-Modified-Since time.
400 Bad RequestLocale not supported.

Get All Valid Fields for an Item Type#

Note: API consumers intending to write to the server should generally use /items/new combined with /itemTypes instead of this request.

GET /itemTypeFields?itemType=book
If-Modified-Since: Mon, 14 Mar 2011 22:30:17 GMT
[
  { "field" : "title", "localized" : "Title" },
  { "field" : "abstractNote", "localized" : "Abstract" },
  ()
]
Common responses
200 OK
304 Not ModifiedNo changes have occurred since If-Modified-Since time.
400 Bad RequestLocale not supported.

Get Valid Creator Types for an Item Type#

GET /itemTypeCreatorTypes?itemType=book
[
  { "creatorType" : "author", "localized" : "Author" },
  { "creatorType" : "editor", "localized" : "Editor" },
  ()
]
Common responses
200 OK
304 Not ModifiedNo changes have occurred since If-Modified-Since time.
400 Bad Request'itemType' is unspecified or invalid; locale not supported.

Get Localized Creator Fields#

GET /creatorFields
If-Modified-Since: Mon, 14 Mar 2011 22:30:17 GMT
[
  { "field" : "firstName", "localized" : "First" },
  { "field" : "lastName", "localized" : "Last" },
  { "field" : "name", "localized" : "Name" }
]
Common responses
304 Not ModifiedNo changes have occurred since If-Modified-Since time.
400 Bad RequestLocale not supported.

Get Template for a New Item#

GET /items/new?itemType=book
If-Modified-Since: Mon, 14 Mar 2011 22:30:17 GMT
{
  "itemType" : "book",
  "title" : "",
  "creators" : [
    {
      "creatorType" : "author",
      "firstName" : "",
      "lastName" : ""
    }
  ],
  "url" : "",
  (...),
  "tags" : [],
  "notes" : []
}
GET /items/new?itemType=note
If-Modified-Since: Mon, 14 Mar 2011 22:30:17 GMT
{
  "itemType" : "note",
  "note" : "",
  "tags" : []
}

Adding attachments is not yet supported.

Common responses
200 OK
304 Not ModifiedNo changes have occurred since If-Modified-Since time.
400 Bad RequestitemType is unspecified or invalid.

Write Requests#

Creating an Item#

POST /users/1/items
Content-Type: application/json
X-Zotero-Write-Token: 19a4f01ad623aa7214f82347e3711f56
{
  "items" : [
    {
      "itemType" : "book",
      "title" : "My Book",
      "creators" : [
        {
          "creatorType":"author",
          "firstName" : "Sam",
          "lastName" : "McAuthor"
        },
        {
          "creatorType":"editor",
          "name" : "John T. Singlefield"
        }
      ],
      "tags" : [
        { "tag" : "awesome" },
        { "tag" : "rad", "type" : 1 }
      ],
      "notes" : [
        {
          "itemType" : "note",
          "note" : "<p>What a <strong>great</strong> book!</p>"
        }
      ]
    }
  ]
}

All fields other than itemType are optional.

Note content will be treated as HTML and sanitized automatically.

Common responses
201 CreatedItem(s) successfully created — see example Atom response below
400 Bad RequestInvalid type/field; unparseable JSON
409 ConflictThe target library is locked.
412 Precondition FailedThe provided X-Zotero-Write-Token has already been submitted.
413 Request Entity Too LargeToo many items submitted

Example 201 Created response:

<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:zapi="http://zotero.org/ns/api">
  <title>Zotero / Zotero User / Items</title>
  <id>http://zotero.org/users/1/items?itemKey=ABCD2345</id>
  <link rel="self" type="application/atom+xml" href="https://api.zotero.org/users/1/items?itemKey=ABCD2345"/>
  <link rel="first" type="application/atom+xml" href="https://api.zotero.org/users/1/items?itemKey=ABCD2345"/>
  <link rel="last" type="application/atom+xml" href="https://api.zotero.org/users/1/items?itemKey=ABCD2345"/>
  <zapi:totalResults>1</zapi:totalResults>
  <zapi:apiVersion>1</zapi:apiVersion>
  <updated>2010-12-17T00:18:51Z</updated>
    <entry>
      <title>My Book</title>
      <author>
          <name>Zotero User</name>
          <uri>http://zotero.org/zuser</uri>
      </author>
      <id>http://zotero.org/users/zuser/items/ABCD2345</id>
      <published>2010-12-17T00:18:51Z</published>
      <updated>2010-12-17T00:18:51Z</updated>
      <link rel="self" type="application/atom+xml" href="https://api.zotero.org/users/1/items/ABCD2345?content=json"/>
      <link rel="alternate" type="text/html" href="http://zotero.org/users/zuser/items/ABCD2345"/>
      <zapi:key>ABCD2345</zapi:key>
      <zapi:itemType>book</zapi:itemType>
      <zapi:creatorSummary>McAuthor</zapi:creatorSummary>
      <zapi:numChildren>1</zapi:numChildren>
      <zapi:numTags>2</zapi:numTags>
      <content type="application/json" etag="8e984e9b2a8fb560b0085b40f6c2c2b7">
        {
          "itemType" : "book",
          "title" : "My Book",
          "creators" : [
            {
              "creatorType" : "author",
              "firstName" : "Sam",
              "lastName" : "McAuthor"
            },
            {
              "creatorType":"editor",
              "name" : "John T. Singlefield"
            }
          ],
          "tags" : [
            { "tag" : "awesome" },
            { "tag" : "rad", "type" : 1 }
          ]
        }
      </content>
    </entry>
</feed>

Creating Multiple Items#

JSON for multiple items can be passed in the items array. A maximum of 50 items can be added in a single request.

Updating an Existing Item#

First, retrieve the current version of the item, specifying JSON as the format for the Atom <content> node:

GET /users/1/items/ABCD2345?content=json

See Creating an Item above for an example response.

Next, modify the JSON and resubmit to the server. Include the value of the <content> node’s etag attribute in the If-Match HTTP header:

PUT /users/1/items/ABCD2345
Content-Type: application/json
If-Match: "8e984e9b2a8fb560b0085b40f6c2c2b7"
{
  "itemType" : "book",
  "title" : "My Amazing Book",
  "creators" : [
    {
      "creatorType":"author",
      "firstName" : "Sam",
      "lastName" : "McAuthor"
    },
    {
      "creatorType":"editor",
      "name" : "John T. Singlefield"
    }
  ],
  "tags" : [
    { "tag" : "awesome" },
    { "tag" : "rad", "type" : 1 }
  ]
}

All fields other than itemType, creators, and tags are optional. If creators and/or tags are empty, any associated creators and/or tags will be removed from the item.

Child notes can be added only with new items. To add child notes to an existing item, POST an items array containing note items to /users/<userID>/items/<itemKey>/children.

PUT requests must include an If-Match header with an ETag provided by a previous request for the item. If the item has been changed on the server since the item was retrieved, the PUT request will be rejected with a 412 Precondition Failed error, and the most recent version of the item will have to be retrieved from the server before changes can be made.

Common responses
200 OKSame as Atom response above, but with updated data.
400 Bad RequestInvalid type/field; unparseable JSON; client did not include ETag.
409 ConflictThe target library is locked.
412 Precondition FailedThe item has changed since retrieval (i.e., the provided ETag no longer matches).

Deleting an Item#

GET /users/1/items/ABCD2345?content=json

DELETE /users/1/items/ABCD2345
If-Match: "8e984e9b2a8fb560b0085b40f6c2c2b7"
Common responses
204 No ContentThe item was deleted.
409 ConflictThe target library is locked.
412 Precondition FailedThe item has changed since retrieval (i.e., the provided ETag no longer matches).

Adding Items to a Collection#

POST /users/1/collections/QRST9876/items

ABCD2345 BCDE3456 CDEF4567 DEFG5678

The POST body is a space-delimited list of item keys from the same library as the collection. Existing items not specified will not be removed from the collection.

Child items cannot be added directly to collections.

Common responses
204 No ContentItems were added to collection.
400 Bad RequestItem not found in library; attempt to add child item to collection.
409 ConflictThe target library is locked.

Removing an Item from a Collection#

DELETE /users/1/collections/QRST9876/items/ABCD2345
Common responses
204 No ContentItem was removed from the collection.
409 ConflictThe target library is locked.

Creating a Collection#

POST /users/1/collections
Content-Type: application/json
X-Zotero-Write-Token: 19a4f01ad623aa7214f82347e3711f56
{
  "name" : "My Collection",
  "parent" : "QRST9876"
}
Common responses
201 CreatedThe collection was created.
409 ConflictThe target library is locked.
412 Precondition FailedThe provided X-Zotero-Write-Token has already been submitted.

Updating an Existing Collection#

GET /users/1/collections/RSTU8765?content=json

PUT /users/1/collections/RSTU8765
Content-Type: application/json
If-Match: "f0ebb2240a57f4115b3ce841d5218fa2"
{
  "name" : "My Collection",
  "parent" : false
}
Common responses
200 OKThe collection was updated.
409 ConflictThe target library is locked.
412 Precondition FailedThe collection has changed since retrieval (i.e., the provided ETag no longer matches).

Deleting a Collection#

GET /users/1/collections/RSTU8765?content=json

DELETE /users/1/collections/RSTU8765
If-Match: "f0ebb2240a57f4115b3ce841d5218fa2"
Common responses
204 No ContentThe collection was deleted.
409 ConflictThe target library is locked.
412 Precondition FailedThe collection has changed since retrieval (i.e., the provided ETag no longer matches).

X-Zotero-Write-Token#

X-Zotero-Write-Token: 19a4f01ad623aa7214f82347e3711f56

X-Zotero-Write-Token is an optional HTTP header, containing a client-generated identifier string between 8 and 32 characters in length, that can be included with item and collection creation requests to prevent them from being processed more than once (e.g., if a user clicks a form submit button twice). The Zotero server caches write tokens for successful requests for 12 hours, and subsequent requests from the same API key using the same write token will be rejected with a 412 Precondition Failed status code. If a request fails, the write token will not be stored.