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 Modified No changes have occurred since If-Modified-Since time.
400 Bad Request Locale 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 Modified No changes have occurred since If-Modified-Since time.
400 Bad Request Locale 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 Modified No changes have occurred since If-Modified-Since time.
400 Bad Request Locale 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 Modified No 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 Modified No changes have occurred since If-Modified-Since time.
400 Bad Request Locale 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 Modified No changes have occurred since If-Modified-Since time.
400 Bad Request itemType 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 Created Item(s) successfully created — see example Atom response below
400 Bad Request Invalid type/field; unparseable JSON
409 Conflict The target library is locked.
412 Precondition Failed The provided X-Zotero-Write-Token has already been submitted.
413 Request Entity Too Large Too 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 OK Same as Atom response above, but with updated data.
400 Bad Request Invalid type/field; unparseable JSON; client did not include ETag.
409 Conflict The target library is locked.
412 Precondition Failed The 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 Content The item was deleted.
409 Conflict The target library is locked.
412 Precondition Failed The 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 Content Items were added to collection.
400 Bad Request Item not found in library; attempt to add child item to collection.
409 Conflict The target library is locked.

Removing an Item from a Collection

DELETE /users/1/collections/QRST9876/items/ABCD2345
Common responses
204 No Content Item was removed from the collection.
409 Conflict The 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 Created The collection was created.
409 Conflict The target library is locked.
412 Precondition Failed The 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 OK The collection was updated.
409 Conflict The target library is locked.
412 Precondition Failed The 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 Content The collection was deleted.
409 Conflict The target library is locked.
412 Precondition Failed The 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.