> ## Documentation Index
> Fetch the complete documentation index at: https://galejames.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Add the Idempotency-Key header

> Add the `Idempotency-Key` header to prevent duplicates when creating books.

This guide explains how to add the `Idempotency-Key` header to prevent duplicate book creation in the BookHub Publisher API v2. Including a unique `Idempotency-Key` is required when creating a book with `POST /v2/books`. For example, if a network error causes you to resend the same request, the idempotency header ensures only one book is created.

## Prerequisites

Before you begin, ensure you meet the following prerequisites:

* Familiarity with the BookHub Publisher API v2.
* A valid JWT for authentication.
* Access to your codebase that integrates with the BookHub Publisher API v2.

## Step 1: Add the `Idempotency-Key` header

When you create a new book using the `POST /v2/books` endpoint, you must include a unique `Idempotency-Key` header in your create request. The `Idempotency-Key` must be a UUID. Generate a new one for each distinct book you create. Store the key with the pending request so you can reuse it if the request needs to be retried after a restart or crash.

> [!NOTE]
>
> Reusing the same `Idempotency-Key` returns the original result instead of creating a second book — this is what makes retries safe. Sending the same book data with a *new* key is treated as a new create request, and returns `409 Conflict` because the ISBN already exists.

```python theme={null}
import requests
import uuid

BASE_URL = "https://api.bookhub.com/api"
TOKEN = "YOUR_JWT_TOKEN"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}

idempotency_key = str(uuid.uuid4())

book_data = {
    "title": "The Design of Everyday Things",
    "author": "Don Norman",
    "description": "A classic book on user-centered design",
    "language": "en-US",
    "publisher": "Basic Books",
    "publishedDate": "2024-01-01",
    "isbn": "978-3-16-148410-0",
    "price": 24.99,
    "coverImages": ["https://example.com/cover.jpg"],
    "genres": ["Design", "Technology"],
    "bookFormat": "Hardcover"
}

try:
    response = requests.post(
        f"{BASE_URL}/v2/books",
        headers={**HEADERS, 'Idempotency-Key': idempotency_key},
        json=book_data
    )
    response.raise_for_status()
    book = response.json()['data']
    if response.status_code == 201:
        print(f"Created: {book['bookId']} — Status: {book['status']}")
    else:  # 200 — idempotent replay, book already existed
        print(f"Already created: {book['bookId']}")
except requests.HTTPError as e:
    status = e.response.status_code
    if status == 409:
        # Same ISBN, different key — the book already exists
        print("Book already exists. Reuse the original Idempotency-Key to retry.")
    elif status == 429:
        reset = e.response.headers.get('X-RateLimit-Reset')
        print(f"Rate limited. Retry after {reset} with the same Idempotency-Key.")
    else:
        print(f"Request failed ({status}): {e.response.json().get('message')}")
```

## Response

A successful request returns a `201 Created` response with the details of the newly created book.

> [!NOTE]
>
> Use a unique `Idempotency-Key` for each distinct book you create — but reuse the same key when retrying a request that may not have completed. The API retains each key for 24 hours. After a key expires, retrying with it is treated as a new create request — which returns `409 Conflict` if the book was already created. Generate a new key only when creating a different book.

For error responses including `400`, `401`, `409`, and `429`, see [Error codes](/reference/reference-api-endpoints#error-codes).

### 201 Created (new book)

```json theme={null}
{
  "status": "success",
  "message": "Book created successfully",
  "data": {
    "bookId": "123e4567-e89b-41d4-a716-426614167005",
    "title": "The Design of Everyday Things",
    "author": "Don Norman",
    "description": "A classic book on user-centered design",
    "language": "en-US",
    "publisher": "Basic Books",
    "publishedDate": "2024-01-01",
    "isbn": "978-3-16-148410-0",
    "price": 24.99,
    "status": "PENDING",
    "coverImages": ["https://example.com/cover.jpg"],
    "genres": ["Design", "Technology"],
    "bookFormat": "Hardcover",
    "createdDate": "2026-05-29T14:00:00Z",
    "updatedDate": "2026-05-29T14:00:00Z"
  }
}
```

If you send the same request again with the same `Idempotency-Key`, the API returns a `200 OK` response with the existing book details.

This is expected behavior — not an error. The API recognizes the duplicate request and returns the existing book rather than creating a new one.

### 200 OK (duplicate request, same key)

```json theme={null}
{
  "status": "success",
  "message": "Book already created",
  "data": {
    "bookId": "123e4567-e89b-41d4-a716-426614167005",
    "title": "The Design of Everyday Things",
    "author": "Don Norman",
    "description": "A classic book on user-centered design",
    "language": "en-US",
    "publisher": "Basic Books",
    "publishedDate": "2024-01-01",
    "isbn": "978-3-16-148410-0",
    "price": 24.99,
    "status": "PENDING",
    "coverImages": ["https://example.com/cover.jpg"],
    "genres": ["Design", "Technology"],
    "bookFormat": "Hardcover",
    "createdDate": "2026-05-29T14:00:00Z",
    "updatedDate": "2026-05-29T14:00:00Z"
  }
}
```

## Step 2: Test idempotency behavior

To verify your implementation, send the create request multiple times using the same `Idempotency-Key`. You should see that the API created only one book, with subsequent create requests returning the existing book details.

Send the same request three times using the same `Idempotency-Key` and `book_data`:

```python theme={null}
for i in range(3):
    response = requests.post(
        f"{BASE_URL}/v2/books",
        headers={**HEADERS, 'Idempotency-Key': idempotency_key},
        json=book_data
    )
    print(f"Request {i+1}: {response.status_code}")
```

The output should show one `201 Created` response followed by two `200 OK` responses with the same book details for the repeated create requests.

## Error handling

| Code | Cause | Resolution |
| - | - | - |
| `400` | Validation failure (for example, a malformed ISBN or a non-UUID `Idempotency-Key`) | Check the `errors` array for the failing `field` and `description`, correct the payload, and retry with the same `Idempotency-Key`. |
| `401` | The JWT is missing, malformed, or expired. | Obtain a new token and retry with the same `Idempotency-Key`. |
| `409` | A book with this ISBN already exists (for example, you sent the same book data with a *new* key) | Reuse the original `Idempotency-Key` for retries. If the book was genuinely already created, no action is needed. |
| `429` | Rate limit exceeded (for example, 150 requests per minute) | Wait until the time in the `X-RateLimit-Reset` header, then retry with the same `Idempotency-Key`. See [Monitor rate limits](/how-to-guides/how-to-guides-monitor-rate-limits). |

For full error schemas, see [Error codes](/reference/reference-api-endpoints#error-codes).

## Next steps

Explore related topics:

### How-to guides

* [Create a book](/quickstart/quickstart) — Full quickstart workflow including book creation.
* [Monitor rate limits](/how-to-guides/how-to-guides-monitor-rate-limits) — Track your API usage to avoid exceeding rate limits.

### Reference

* [Code examples](/reference/reference-code-examples) — Copy code samples for book creation, sorting by creation date, handling removed title sorting, and tracking performance with `hitCount`.
* [Release notes](/reference/reference-release-notes) — Explore all changes in BookHub Publisher API v2.

***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.