Typicode APIjsonplaceholder.typicode.com ↗
Access JSONPlaceholder's full fake REST API: posts, comments, albums, photos, todos, and users. 40 endpoints for testing and prototyping.
What is the Typicode API?
This API exposes all 40 endpoints of JSONPlaceholder, a static fake REST dataset commonly used for testing and prototyping. It covers six resource types — posts, comments, albums, photos, todos, and users — with full CRUD operations on each. For example, get_posts returns an array of 100 post objects (fields: userId, id, title, body), and you can filter by user_id to scope results to any of the 10 fictional users in the dataset.
curl -X GET 'https://api.parse.bot/scraper/fb23009a-bb34-498d-8d88-5b085f983739/get_posts?user_id=1' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace jsonplaceholder-typicode-com-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""JSONPlaceholder SDK — bounded, re-runnable walkthrough."""
from parse_apis.jsonplaceholder_api import JSONPlaceholder, Completed, UserId, ResourceNotFound
client = JSONPlaceholder()
# List posts filtered by user ID using the UserId enum.
for post in client.posts.list(user_id=UserId._1, limit=3):
print(f"Post #{post.id}: {post.title[:50]}")
# Fetch a user and explore sub-resources.
user = client.users.list(limit=1).first()
if user:
print(f"User: {user.name} (@{user.username}), company={user.company.name}")
for todo in user.todos.list(limit=3):
print(f" Todo #{todo.id}: completed={todo.completed}, {todo.title[:40]}")
# Drill into a post's comments via sub-resource.
first_post = client.posts.list(limit=1).first()
if first_post:
for comment in first_post.comments.list(limit=2):
print(f" Comment by {comment.email}: {comment.body[:40]}...")
# Create a new todo with Completed enum.
new_todo = client.todos.create(title="Buy groceries", user_id=1, completed=Completed.FALSE)
print(f"Created todo #{new_todo.id}: {new_todo.title}")
# Typed error handling on a non-existent resource.
try:
missing = client.post(id=99999).refresh()
except ResourceNotFound as exc:
print(f"Caught ResourceNotFound: {exc}")
# Album photos via sub-resource navigation.
album = client.album(id=1).refresh()
photo = album.photos.list(limit=1).first()
if photo:
print(f"Album '{album.title}' photo: {photo.title}, url={photo.url}")
print("Exercised: posts.list / users.list / user.todos.list / post.comments.list / todos.create / post.refresh (error) / album.photos.list")
Get all posts or filter by userId. Returns post objects wrapped under 'items'. The dataset contains 100 posts spanning userId 1-10 with 10 posts per user.
| Param | Type | Description |
|---|---|---|
| user_id | integer | Filter posts by user ID (1-10). |
{
"type": "object",
"fields": {
"items": "array of post objects, each with userId, id, title, body"
},
"sample": {
"data": {
"items": [
{
"id": 1,
"body": "quia et suscipit...",
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"userId": 1
}
]
},
"status": "success"
}
}About the Typicode API
Posts and Comments
The posts collection contains 100 records spread evenly across user IDs 1–10. get_posts accepts an optional user_id integer to return only that user's 10 posts. get_post retrieves a single record by post_id (1–100) and returns userId, id, title, and body. The comments collection has 500 records, exactly 5 per post. You can fetch them either via get_post_comments (nested path, requires post_id) or via get_comments with an optional post_id filter. Each comment object carries postId, id, name, email, and body.
Write Operations
All six resource types support create, full-update (PUT), partial-update (PATCH), and delete verbs. create_post expects title, body, and user_id; it always echoes back id: 101 because the dataset is static — no record is actually persisted. The same mock behavior applies to update_post, patch_post, and delete_post. patch_post is the only write endpoint that accepts a subset of fields; omitted fields reflect the original stored values in the response.
Albums and Photos
get_albums returns 100 album objects (userId, id, title), filterable by user_id. get_album_photos uses the nested resource path and returns all 50 photos for a given album. Each photo object includes albumId, id, title, url, and thumbnailUrl. The url and thumbnailUrl fields point to placeholder image URLs in the JSONPlaceholder dataset — they are not real hosted images.
The Typicode API is a managed, monitored endpoint for jsonplaceholder.typicode.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when jsonplaceholder.typicode.com changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official jsonplaceholder.typicode.com API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Prototype a blog UI against real-shaped post and comment data before wiring a production backend.
- Test pagination logic using the fixed 100-post or 500-comment dataset with predictable record counts.
- Validate client-side form submission flows using the mock
create_postandcreate_commentendpoints. - Build and test a photo gallery component using
get_album_photoswhich returnsurlandthumbnailUrlper photo. - Teach REST API fundamentals — GET, POST, PUT, PATCH, DELETE — using a live endpoint with known response shapes.
- Integration-test error handling by requesting out-of-range IDs (e.g., post_id > 100) to observe 404 behavior.
- Verify that a PATCH implementation correctly merges partial fields using
patch_postorpatch_comment.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does JSONPlaceholder have an official developer API?+
What does `get_post_comments` return compared to `get_comments`?+
get_post_comments uses the nested /posts/{id}/comments path and requires a post_id; it always returns exactly 5 comment objects for that post. get_comments hits the flat /comments collection and accepts an optional post_id query parameter. Both return identical comment object shapes: postId, id, name, email, and body.Do write operations (create, update, delete) actually modify data?+
create_post always returns id: 101, create_comment always returns id: 501, and delete endpoints return an empty object. No state is persisted between requests.Does this API cover the todos and users resources?+
Can I filter posts or comments by fields other than user ID or post ID?+
get_posts filters only by user_id and get_comments filters only by post_id; no full-text, date, or title filtering is available in the dataset. You can fork this API on Parse and revise it to add client-side filtering logic over the returned arrays.