OverDrive Developers

Holds API

The Holds API is used to manage and place holds for a specific patron.

Note: The examples below show our production API URL. If you're using our integration environment, use https://integration-patron.api.overdrive.com. For more information on the integration environment, please see our Getting started guide.

Using the Holds API

Using POST, GET, and DELETE commands, you can use the Holds API to retrieve a list of a user's holds, place a hold on a user's behalf, or remove an existing hold.

Available endpoint functions

  • Place a hold: Use a POST request to the holds endpoint to place holds on behalf of a patron.
  • GET patron holds: Make this request to list a patron's current holds or find a specific held title.
  • Update a hold: Use a PUT request to update the patron's email address for a specific hold.
  • Suspend a hold: Use a POST request to suspend a hold that a patron has placed on a title.
  • Remove a hold: Use a DELETE request to remove a specific hold from a patron's account.

Place a hold (POST)

To place a hold, make a POST request to the /v1/patrons/me/holds endpoint with the following fields:

FieldExplanation
id
Required
The title's unique identifier. Can be either the title's reserveId or crossRefId.
emailAddress
Required
The patron's email address, where they'll be notified when the title is available to borrow.
ignoreHoldEmail
Optional
When set to true, a patron will not need to include an emailAddress to place a title on hold (and the parameter will not need to be passed in the POST request).

You may want to use ignoreHoldEmail if your website or app needs an option for COPPA compliance. If this is the case, you won't have to supply an email address in the POST request, but you'll still be able to place the title on hold for the user.

Here's an example of a simple holds request:

POST https://patron.api.overdrive.com/v1/patrons/me/holds
User-Agent: {Your application}
Authorization: Bearer {OAuth patron access token}
Content-Type: application/json; charset=utf-8
Host: patron.api.overdrive.com
Content-Length: 178
Expect: 100-continue

{
    "fields": [
        {
            "name": "id",
            "value": "0D85564B-A4B3-43D5-875D-1DF3CA06AE65"
        },
        {
            "name": "emailAddress",
            "value": "YourEmailHere@overdrive.com"
        }
    ]
}

When you've successfully placed a hold, you'll get a POST response that includes specific hold information for the title, which looks something like this:

201 Created
Pragma: no-cache
X-Frame-Options: deny
Content-Length: 694
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Date: Mon, 03 Jan 2022 17:22:16 GMT
Expires: -1
Location: https://patron.api.overdrive.com/v1/patrons/me/holds/0D85564B-A4B3-43D5-875D-1DF3CA06AE65

{
    "reserveId": "0D85564B-A4B3-43D5-875D-1DF3CA06AE65",
    "crossRefId": 25475,
    "emailAddress": "YourEmailHere@overdrive.com",
    "holdListPosition": 1,
    "numberOfHolds": 1,
    "holdPlacedDate": "2013-09-27T13:22:17.087",
    "links": {
        "self": {
            "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/0D85564B-A4B3-43D5-875D-1DF3CA06AE65",
            "type": "application/vnd.overdrive.content.api+json"
        },
        "metadata": {
            "href": "https://api.overdrive.com/v1/collections/P1BPg0AAA24/products/0D85564B-A4B3-43D5-875D-1DF3CA06AE65/metadata",
            "type": "application/vnd.overdrive.api+json"
        }
    },
    "actions": {
        "removeHold": {
            "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/0D85564B-A4B3-43D5-875D-1DF3CA06AE65",
            "method": "delete"
        }
    }
}

GET a list of a patron's holds

Send a GET command to the holds endpoint to get a list of current holds on a patron's account as shown below.

GET https://patron.api.overdrive.com/v1/patrons/me/holds
User-Agent: {Your application}
Authorization: Bearer {OAuth patron access token}
Host: patron.api.overdrive.com
Connection: Keep-Alive

This GET response includes a list of titles that the authenticated user currently has on hold from his or her library.

200 OK
Pragma: no-cache
X-Frame-Options: deny
Content-Length: 2854
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Date: Mon, 03 Jan 2022 20:11:14 GMT
Expires: -1

{
    "totalItems": 2,
    "holds": [
        {
            "reserveId": "AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD",
            "crossRefId": 217936,
            "emailAddress": "yourEmailHere@overdrive.com",
            "autoCheckout": false,
            "holdListPosition": 2,
            "numberOfHolds": 2,
            "holdSuspension": { 
                "suspensionType": "indefinite", 
                "numberOfDays": 0 
            },
            "holdPlacedDate": "2021-12-31T11:49:39Z",
            "links": {
                "self": { 
                    "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD", 
                    "type": "application/vnd.overdrive.circulation.api+json" 
                },
                "metadata": { 
                    "href": "https://api.overdrive.com/v1/collections/v1P2BAwAAAMMEAAA18/products/AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD/metadata", 
                    "type": "application/vnd.overdrive.api+json" 
                }
            },
            "actions": {
                "editHold": {
                    "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD",
                    "type": "application/vnd.overdrive.circulation.api+json",
                    "method": "put",
                    "fields": [ 
                        { 
                            "name": "emailAddress", 
                            "type": "text", 
                            "optional": true 
                        }
                    ]
                },
                "removeHold": { 
                    "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD", 
                    "method": "delete" 
                },
                "addSuspension": {
                    "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD/suspension",
                    "method": "post",
                    "fields": [
                        { 
                            "name": "suspensionType", 
                            "type": "text", 
                            "value": "", 
                            "options": [ 
                                "indefinite", 
                                "limited" 
                            ], 
                            "optional": false 
                        },
                        { 
                            "name": "numberOfDays", 
                            "type": "number", 
                            "value": "", 
                            "optional": true 
                        }
                    ]
                },
                "releaseSuspension": { 
                    "href": "https://patron.api.overdrive.com.oddev/v1/patrons/me/holds/AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD/suspension", 
                    "method": "delete" 
                }
            }
        },
        {
            "reserveId": "622708F6-78D7-453A-A7C5-3FE6853F3167",
            "crossRefId": 789876,
            "emailAddress": "yourEmailHere@overdrive.com",
            "autoCheckout": false,
            "holdListPosition": 1,
            "numberOfHolds": 1,
            "holdPlacedDate": "2021-07-14T10:44:35Z",
            "holdExpires": "2022-07-16T14:49:48Z",
            "links": {
                "self": { 
                    "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/622708F6-78D7-453A-A7C5-3FE6853F3167", 
                    "type": "application/vnd.overdrive.circulation.api+json" 
                },
                "metadata": { 
                    "href": "https://api.overdrive.com/v1/collections/v1P2BAwAAAMMEAAA18/products/622708F6-78D7-453A-A7C5-3FE6853F3167/metadata", 
                    "type": "application/vnd.overdrive.api+json" 
                }
            },
            "actions": {
                "removeHold": { 
                    "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/622708F6-78D7-453A-A7C5-3FE6853F3167", 
                    "method": "delete" 
                },
                "checkout": {
                    "href": "https://patron.api.overdrive.com/v1/patrons/me/checkouts",
                    "type": "application/vnd.overdrive.circulation.api+json",
                    "method": "post",
                    "fields": [
                        { 
                            "name": "reserveId", 
                            "type": "text", 
                            "value": "622708F6-78D7-453A-A7C5-3FE6853F3167" 
                        },
                        { 
                            "name": "formatType", 
                            "type": "text", 
                            "value": "", 
                            "options": [ 
                                "ebook-epub-adobe", 
                                "ebook-kindle" 
                            ], 
                            "optional": true 
                        }
                    ]
                }
            }
        }
    ],
    "links": {
        "self": { 
            "href": "https://patron.api.overdrive.com/v1/patrons/me/holds", 
            "type": "application/vnd.overdrive.circulation.api+json" 
        }
    }
}

Take special note of the holdListPosition and numberOfHolds values. In the first title listed in the response above, the holdListPosition is "2." The numberOfHolds is also "2." That means this user is the 2nd person in line for the title, and there are a total of two people who have the title on hold.

The second title in the example above is ready to borrow because the holdListPosition and numberOfHolds values are both "1." Additionally, checkout appears within the list of available actions, letting you know that the title can be checked out.

Update a hold (PUT)

You can update a user's emailAddress for a specific hold by sending a PUT request to the holds endpoint. You'll need to include the id from the original hold and the new emailAddress.

Two quick notes:

  • You won't be able to change the ignoreHoldEmail value after it's set in the original POST request.
  • Once the title on hold becomes available to check out, you won't be able to update it using a PUT request.

Here's an example of what your request may look like if you wanted to update a user's email address:

PUT https://patron.api.overdrive.com/v1/patrons/me/holds/AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD
Content-Type: application/json
Authorization: Bearer {OAuth patron access token}
Host: patron.api.overdrive.com
Content-Length: 428

{
    "fields": [
        { 
            "name": "id", 
            "value": "AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD" 
        },
        { 
            "name": "emailAddress", 
            "value": "newEmailAddress@overdrive.com" 
        },
    ]
}

If your request was successful, you'll be returned a simple 204 NoContent response:

204 NoContent
Pragma: no-cache
X-Frame-Options: deny
Cache-Control: no-cache
Date: Wed, 05 Jan 2022 13:41:15 GMT
Expires: -1

Suspending a hold (POST)

To suspend a hold on a title, make a POST request that includes the id (reserveId or crossRefId), emailAddress, and suspensionType. If you're defining a "limited" suspension, you'll also need to include a duration for the numberOfDays value.

Note: Suspending a hold is useful for end users that want some control over when a title will become available for them to borrow. It's like waiting in line at the grocery store until you get to the front and then holding your place until you're ready while letting the people behind you go past to check out.

In your POST request, emailAddress is the email address that was originally used to place the hold. There are also two types of suspensions (suspensionType): "indefinite" and "limited." The URL must include the id for the title that's on hold.

Here's an example of an indefinite suspension POST request:

POST: https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584/suspension
User-Agent:{Your application}
Authorization: Bearer {OAuth patron access token}
Content-Type: application/json; charset=utf-8
Host: patron.api.overdrive.com
Content-Length: 114
Expect: 100-continue

{
    "fields": [
        {
            "name": "emailAddress",
            "value": "YourEmailHere@overdrive.com"
        },
        {
            "name": "suspensionType",
            "value": "indefinite"
        }
    ]
}

Note the "indefinite" value for suspensionType. This means the suspension won't expire. Instead, it must be removed for the title to become available for the user. The response returned from a successful indefinite suspension request looks like this:

201 CREATED
Pragma: no-cache
X-Frame-Options: deny
Content-Length: 736
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Date: Mon, 03 Jan 2022 13:50:29 GMT
Expires: -1

{
    "reserveId": "76C1B7D0-17F4-4C05-8397-C66C17411584",
    "crossRefId": 784864,
    "emailAddress": "YourEmailHere@overdrive.com",
    "holdListPosition": 2,
    "numberOfHolds": 2,
    "holdSuspension": {
        "suspensionType": "indefinite",
        "numberOfDays": 0
    },
    "holdPlacedDate": "2021-12-02T09:49:48Z",
    "links": {
        "self": {
            "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584",
            "type": "application/vnd.overdrive.circulation.api+json"
        }
    },
    "actions": {
        "removeHold": {
            "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584",
            "method": "delete"
        },
        "releaseSuspension": {
            "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584/suspension",
            "method": "delete"
        }
    }
}

If you want to suspend a hold for a specific amount of time, define numberOfDays and set the suspensionType to "limited" as shown in this example:

POST: https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584/suspension
User-Agent:{Your application}
Authorization: Bearer {OAuth patron access token}
Content-Type: application/json; charset=utf-8
Host: patron.api.overdrive.com
Content-Length: 147
Expect: 100-continue

{
    "fields": [
        {
            "name": "emailAddress",
            "value": "YourEmailHere@overdrive.com"
	},
	{
            "name": "suspensionType",
            "value": "limited"
	},
	{
            "name": "numberOfDays",
            "value": "2"
	}
    ]
}

The numberOfDays field has a value of "2," which means this POST will put a suspension on the hold for two days. Here's an example of a successful response:

201 Created
Pragma: no-cache
X-Frame-Options: deny
Content-Length: 733
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Date: Mon, 03 Jan 2022 13:50:23 GMT
Expires: -1
		
{
    "reserveId": "76C1B7D0-17F4-4C05-8397-C66C17411584",
    "crossRefId": 784864,
    "emailAddress": "YourEmailHere@overdrive.com",
    "holdListPosition": 2,
    "numberOfHolds": 2,
    "holdSuspension": {
        "suspensionType": "limited",
        "numberOfDays": 2
    },
    "holdPlacedDate": "2021-12-02T09:49:48Z",
    "links": {
        "self": {
            "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584",
            "type": "application/vnd.overdrive.circulation.api+json"
        }
    },
    "actions": {
        "removeHold": {
            "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584",
            "method": "delete"
        },
        "releaseSuspension": {
            "href": "https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584/suspension",
            "method": "delete"
        }
    }
}

Updating a suspended hold (PUT)

If you need to change any value for a suspended hold, you can do so by sending a PUT request to the holds suspension endpoint. Here's how you'll structure the URL:

 https://patron.api.overdrive.com/v1/patrons/me/holds/{id}/suspension

The id in the URL is the same ID as the original hold request (either a reserveId or crossRefId).

Like the original suspension POST, you'll need to provide all three fields (emailAddress, suspensionType, and numberOfDays) in this PUT request.

In this example request, we're updating both the emailAddress and numberOfDays fields from the example above:

PUT https://patron.api.overdrive.com/v1/patrons/me/holds/AEC21DDE-BF3B-422A-B0EF-1B9D1D146FFD/suspension
User-Agent: {Your application}
Content-Type: application/json
Authorization: Bearer {OAuth patron access token} 
Host: patron.api.overdrive.com
Content-Length: 312

{
    "fields": [
        { 
            "name": "emailAddress", 
            "value": "newEmailAddress@overdrive.com" 
	},
	{ 
            "name": "suspensionType", 
            "value": "limited" 
	},
	{ 
            "name": "numberOfDays", 
            "value": "5" 
	}
    ]
}

When you've successfully updated your suspended hold, you'll see a response like this:

204 NoContent
Pragma: no-cache
X-Frame-Options: deny
Cache-Control: no-cache
Date: Wed, 05 Jan 2022 13:39:44 GMT
Expires: -1

Deleting a suspended hold

If you want to remove a hold suspension, you can do it with a DELETE request sent to the suspension endpoint. This will not remove the hold, only the hold suspension. Users will maintain their place in the holds waiting list once the suspension is removed.

Here's an example of a hold suspension DELETE request:

DELETE: https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584/suspension
User-Agent:{Your application}
Authorization: Bearer {OAuth patron access token}
Content-Type: application/json; charset=utf-8
Host: integration-patron.api.overdrive.com

A successful DELETE request will return a response like this:

204 NoContent
Pragma: no-cache
X-Frame-Options: deny
Cache-Control: no-cache
Date: Wed, 02 Jul 2014 13:50:37 GMT
Expires: -1

Removing a hold (DELETE)

Make a DELETE request to the holds endpoint to completely remove a hold from a patron's account as shown in the example below.

DELETE https://patron.api.overdrive.com/v1/patrons/me/holds/76C1B7D0-17F4-4C05-8397-C66C17411584
User-Agent: {Your application}
Authorization: Bearer {OAuth patron access token}
Host: patron.api.overdrive.com
Connection: Keep-Alive

This returns a simple 204 NoContent response when you've successfully removed a hold:

204 NoContent
Pragma: no-cache
X-Frame-Options: deny
Cache-Control: no-cache
Date: Wed, 25 Sep 2013 13:25:11 GMT
Expires: -1