REST API design with semantic HTTP methods, status codes, and resource modeling. Use when designing new APIs or reviewing existing API designs.
From api-developmentnpx claudepluginhub sethdford/claude-skills --plugin engineer-api-developmentThis skill is limited to using the following tools:
examples/example-output.mdtemplate.mdEnables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Designing HTTP APIs following REST principles: resources (nouns), methods (verbs), semantic status codes, and hypermedia.
You are designing or reviewing a REST API. Your role is to:
REST is architectural style, not HTTP CRUD framework. Treat it with discipline.
Based on Roy Fielding's dissertation and REST maturity model (Richardson Level 0-3):
Ask: "What are the nouns in this domain?"
Example (E-commerce API):
For each resource, define:
/resource - collection of resource
/resource/{id} - individual resource
/resource/{id}/sub - sub-resource (collection)
/resource/{id}/sub/{id} - individual sub-resource
Good paths:
GET /users - list all users
POST /users - create user
GET /users/123 - get user 123
PUT /users/123 - replace user 123
PATCH /users/123 - partially update user 123
DELETE /users/123 - delete user 123
GET /users/123/orders - get user 123's orders
POST /users/123/orders - create order for user 123
Bad paths (RPC-style, avoid):
GET /getUser?id=123
GET /user/create
POST /user?action=update
GET /deleteUser?id=123
Example:
POST /orders - create NEW order → 201 Created
PUT /orders/123 - REPLACE entire order (all fields) → 200 OK
PATCH /orders/123 - UPDATE some fields → 200 OK
GET /orders/123 - RETRIEVE order → 200 OK
DELETE /orders/123 - REMOVE order → 204 No Content (or 200)
Success:
200 OK - Request succeeded, response includes result201 Created - Resource created; response includes resource and Location header202 Accepted - Request accepted for processing (async operations)204 No Content - Success but no response body (DELETE often returns this)Redirection:
301 Moved Permanently - Resource moved to new URL303 See Other - Result is at a different URL (use for POST redirect)304 Not Modified - Resource unchanged since client's If-Modified-SinceClient Error:
400 Bad Request - Malformed request (missing field, invalid JSON)401 Unauthorized - Missing authentication403 Forbidden - Authenticated but no permission404 Not Found - Resource doesn't exist409 Conflict - Request conflicts with current state (e.g., duplicate email)422 Unprocessable Entity - Well-formed but semantically invalid (e.g., invalid email format)Server Error:
500 Internal Server Error - Server bug, not client's fault503 Service Unavailable - Server overloaded or downDefine a standard error response:
{
"error": {
"code": "INVALID_EMAIL",
"message": "Email address is invalid",
"details": {
"field": "email",
"value": "not-an-email"
}
}
}
Use same error structure for ALL endpoints. Clients can parse errors consistently.
Idempotent operations (safe to retry):
Non-idempotent operations (retrying causes problems):
For non-idempotent operations, require client to provide idempotency key:
POST /orders
Idempotency-Key: "550e8400-e29b-41d4-a716-446655440000"
Content-Type: application/json
{ "items": [...], "payment": "credit_card" }
Server stores key → response mapping. If client retries with same key, return cached response (no duplicate order).
Self-describing API: responses include links to related resources.
{
"id": 123,
"name": "John",
"email": "john@example.com",
"_links": {
"self": { "href": "/users/123" },
"all_users": { "href": "/users" },
"orders": { "href": "/users/123/orders" }
}
}
Benefits: Clients can discover endpoints without hardcoding URLs.
For large collections, paginate:
GET /users?page=2&limit=20
GET /users?offset=40&limit=20
GET /users?cursor=abc123&limit=20 (cursor-based, better for distributed systems)
Response includes pagination metadata:
{
"data": [...],
"pagination": {
"page": 2,
"limit": 20,
"total": 500,
"next": "/users?page=3&limit=20"
}
}
Every endpoint needs documentation showing:
When designing an API, deliver:
Domain: Create, update, retrieve orders.
Resources: User, Order, OrderItem, Product
Endpoints:
Users
GET /users - list users
POST /users - create user
GET /users/{id} - get user
PUT /users/{id} - replace user
DELETE /users/{id} - delete user
Orders
GET /orders - list orders (paginated)
POST /orders - create order
GET /orders/{id} - get order
PUT /orders/{id} - replace order
DELETE /orders/{id} - cancel order
Order Items (sub-resource)
GET /orders/{id}/items - get order items
POST /orders/{id}/items - add item to order
Request Examples:
POST /orders HTTP/1.1
Idempotency-Key: "550e8400-e29b-41d4-a716-446655440000"
Content-Type: application/json
{
"user_id": 123,
"items": [
{"product_id": 456, "quantity": 2},
{"product_id": 789, "quantity": 1}
],
"shipping_address": {
"street": "123 Main St",
"city": "Springfield",
"zip": "12345"
}
}
Response (201 Created):
{
"id": 999,
"user_id": 123,
"status": "pending",
"created_at": "2026-03-11T14:30:00Z",
"items": [...],
"_links": {
"self": { "href": "/orders/999" },
"cancel": { "href": "/orders/999", "method": "DELETE" },
"user": { "href": "/users/123" }
}
}
/v1/) or header (Accept: application/vnd.api+json;version=1)