GET /v1/status/{requestId} #
Check the progress and results of a book generation job.
Overview #
After starting a generation with POST /v1/book, use this endpoint to poll for progress and retrieve results. The endpoint returns the current status, progress percentage, and — when complete — the download URL.
Endpoint #
GET https://api.nelliewriter.com/v1/status/{requestId}
Authentication #
Not required. This is a public endpoint. Anyone with the requestId can check status.
💡 Tip: Request IDs are UUIDs and effectively temporary passwords, providing security through obscurity.
Path Parameters #
| Parameter | Type | Description |
|---|---|---|
requestId |
string | The job ID returned by POST /v1/book |
Example Requests #
cURL #
curl https://api.nelliewriter.com/v1/status/abcd1234-ef56-7890-abcd-12ef34567890
Python SDK #
from nellie_api import Nellie
client = Nellie(api_key="nel_your_api_key")
status = client.books.retrieve("abcd1234-ef56-7890-abcd-12ef34567890")
print(f"Status: {status.status}")
print(f"Progress: {status.progress}%")
if status.is_successful():
print(f"Download: {status.result_url}")
Python (requests) #
import requests
request_id = "abcd1234-ef56-7890-abcd-12ef34567890"
response = requests.get(f"https://api.nelliewriter.com/v1/status/{request_id}")
data = response.json()
print(f"Status: {data['status']} ({data['progress']}%)")
Response #
Queued #
Job is waiting in the queue:
{
"requestId": "abcd1234-ef56-7890-abcd-12ef34567890",
"status": "queued",
"progress": 0,
"messages": [
"Request received, waiting in queue..."
],
"createdAt": "2025-12-03T10:30:00Z",
"completedAt": null,
"creditsUsed": 0
}
Processing #
Job is actively generating:
{
"requestId": "abcd1234-ef56-7890-abcd-12ef34567890",
"status": "processing",
"progress": 45,
"messages": [
"Request received, starting job...",
"Generating outline...",
"Creating characters...",
"Writing Chapter 1..."
],
"createdAt": "2025-12-03T10:30:00Z",
"completedAt": null,
"creditsUsed": 0
}
Completed #
Job finished successfully:
{
"requestId": "abcd1234-ef56-7890-abcd-12ef34567890",
"status": "completed",
"progress": 100,
"messages": [
"processing...",
],
"createdAt": "2025-12-03T10:30:00Z",
"completedAt": "2025-12-03T10:55:00Z",
"creditsUsed": 250,
"resultUrl": "https://api.nelliewriter.com/v1/download/abcd1234-ef56-7890-abcd-12ef34567890"
}
Failed #
Job encountered an error:
{
"requestId": "abcd1234-ef56-7890-abcd-12ef34567890",
"status": "failed",
"progress": 34,
"messages": [
"processing...",
"Error: Insufficient credits"
],
"createdAt": "2025-12-03T10:30:00Z",
"completedAt": "2025-12-03T10:32:00Z",
"creditsUsed": 0,
"error": "Insufficient credits",
"errorMessage": "Insufficient credits"
}
Response Fields #
| Field | Type | Description | |
|---|---|---|---|
requestId |
string | The job identifier | |
status |
string | Current status (see below) | |
progress |
integer | Completion percentage (0-100) | |
messages |
array | Log of loading steps | |
createdAt |
string | ISO 8601 timestamp when job was created | |
completedAt |
string | null | ISO 8601 timestamp when job finished |
creditsUsed |
integer | Credits consumed | |
resultUrl |
string | Download URL (only when completed) | |
error |
string | Error description (only when failed) | |
errorMessage |
string | Error description (alias for error) |
Status Values #
| Status | Description |
|---|---|
queued |
Waiting in the generation queue |
processing |
Actively generating content |
completed |
Successfully finished |
failed |
Generation failed |
Error Response #
404 Not Found #
{
"success": false,
"error": "Request not found",
"errorCode": "NOT_FOUND"
}
This occurs when:
- The
requestIdis incorrect - The
requestIddoesn’t exist - The
requestIdformat is invalid
Polling Strategy #
Recommended Approach #
import time
from nellie_api import Nellie
client = Nellie(api_key="nel_...")
# Start a job
book = client.books.create(prompt="A mystery novel")
# Poll every 2 minutes
while True:
status = client.books.retrieve(book.request_id)
print(f"Progress: {status.progress}%")
if status.status == "completed":
print(f"Done! Download: {status.result_url}")
break
elif status.status == "failed":
print(f"Failed: {status.error}")
break
time.sleep(120) # Wait 2 minutes
Using wait_for_completion (SDK) #
The Python SDK provides a built-in polling helper:
from nellie_api import Nellie
client = Nellie(api_key="nel_...")
book = client.books.create(prompt="A mystery novel")
# Blocks until complete
result = client.books.wait_for_completion(
book.request_id,
poll_interval=120, # Check every 2 minutes (min: 60s)
timeout=7200, # Max wait: 2 hours
on_progress=lambda s: print(f"Progress: {s.progress}%")
)
if result.is_successful():
print(f"Download: {result.result_url}")
else:
print(f"Failed: {result.error}")
Polling Guidelines #
| ✅ DO | ❌ DON’T |
|---|---|
| Poll every 2 minutes (120s) | Poll faster than every 60 seconds |
| Use webhooks when possible | Busy-loop without delays |
| Handle timeouts gracefully | Assume jobs complete quickly |
| Log progress for debugging | Ignore the messages array |
Using the Result URL #
The resultUrl is a signed URL that:
- Generates a fresh signed download link on each request (valid for 1 hour)
- Can be downloaded directly via HTTP GET
# Download the generated book
curl -L -o my_book.pdf "https://api.nelliewriter.com/v1/download/abcd1234-ef56-7890-abcd-12ef34567890"
import requests
response = requests.get(result.result_url)
with open("my_book.pdf", "wb") as f:
f.write(response.content)
Webhooks Alternative #
Instead of polling, provide a webhook_url when creating the job to receive a POST notification when it completes:
book = client.books.create(
prompt="A mystery novel",
webhook_url="https://myapp.com/webhooks/nellie"
)
# No need to poll -- you'll receive a webhook when done
See Webhooks for details.
Related Endpoints #
- POST /v1/book — Start a generation job
- GET /v1/usage — View credit history
- Webhooks — Receive push notifications instead of polling
- Rate Limits — Understand polling limits
- Troubleshooting — Debug failed jobs