REST API Design skill for Codex

Endpoints clients can predict before reading docs. Codex inventories the conventions your API already uses, then designs new endpoints to match them: plural resource paths, a status-code decision table, RFC 9457 error bodies with stable codes, whitelisted filters and sorts, ETag concurrency and 202-based long-running operations. Reviews end with a breaking-change check against the existing contract.

  • Backend & APIs
  • $rest-api-design
  • 171 lines
  • 2 files
  • ~1,950 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- rest-api-design

Installs to ~/.agents/skills/rest-api-design/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $rest-api-design, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Designs and reviews HTTP/JSON REST APIs - resource naming, methods, status codes, error bodies, filtering and sorting parameters, PATCH semantics, conditional requests and long-running operations - so every endpoint behaves the same way. Use when adding or changing endpoints, writing a new service's public API, choosing between 400/409/422, reviewing route files or controllers for consistency, or when clients complain the API is unpredictable.

Use it when

  • Adding endpoints to an HTTP/JSON API
  • Standardising status codes and error bodies across a service
  • Designing filter, sort and partial-update behaviour
  • Reviewing a controller or route file before it ships publicly

Use something else when

How to check the result

Call each endpoint with curl -i and confirm the status code, Location/ETag headers and error body match the table; diff the OpenAPI spec for unintended breaking changes.

The mistake it prevents

Returning 200 with an error flag in the body, which breaks client retries, caching and monitoring that all key off the status code.

~/.agents/skills/rest-api-design/SKILL.md

--- name: rest-api-design description: Designs and reviews HTTP/JSON REST APIs - resource naming, methods, status codes, error bodies, filtering and sorting parameters, PATCH semantics,… license: MIT ---

A good REST API is boring: once a client has used two endpoints, it can predict the URL, method, status code, error shape and filter syntax of the third. Consistency with the API’s existing conventions beats any individual “better” choice.

Workflow

- [ ] 1. Inventory the existing conventions
- [ ] 2. Model resources and relationships
- [ ] 3. Assign methods and status codes
- [ ] 4. Define request/response bodies and the error shape
- [ ] 5. Add query conventions (filter, sort, fields, pagination)
- [ ] 6. Handle concurrency, async work and retries
- [ ] 7. Write the contract and contract tests

1. Inventory before designing

  • Read AGENTS.md for API conventions, then any OpenAPI file (openapi.yaml, openapi.json, docs/api/) and two or three existing route handlers.
  • Record: casing of JSON fields (camelCase vs snake_case), ID format, timestamp format, envelope or no envelope, error body shape, pagination style, auth scheme.
  • If conventions conflict across the codebase, follow the newest, most-used pattern and flag the inconsistency instead of inventing a third.

2. Model resources

  • Nouns, plural, lowercase, hyphenated: /invoices, /invoices/{invoiceId}/line-items.
  • Nest at most one level, and only for true containment. If a child has a global ID, also expose it top-level: /line-items/{id}.
  • IDs are opaque strings to clients, even when they are integers in the database. Prefer non-sequential IDs (UUIDv7, ULID, prefixed IDs like inv_...) for public APIs.
  • Actions that do not map to CRUD become either a sub-resource that is created (POST /invoices/{id}/payments) or, as a last resort, a verb sub-path (POST /invoices/{id}:void or /invoices/{id}/void). Pick one style and keep it.

3. Methods and status codes

MethodUse forSuccessIdempotent
GETRead a resource or collection200yes
POSTCreate in a collection, or trigger an action201 + Location, or 200/202no (make it so with idempotency-keys)
PUTFull replacement at a known URL200 or 204yes
PATCHPartial update200 with the updated resourcenot inherently
DELETERemove204 (or 202 if async)yes (repeat returns 204 or 404, pick one)

Error status decision rules:

SituationCode
Malformed JSON, wrong types, unknown query param you reject400
No or invalid credentials401 with WWW-Authenticate
Authenticated but not allowed403 (or 404 to hide existence)
Resource absent, or hidden from this caller404
Method not supported on this path405 with Allow
State conflict: duplicate unique field, invalid state transition409
If-Match ETag stale412
Update without required If-Match428
Well-formed but fails business validation422
Rate or quota exceeded429 with Retry-After
Unhandled server fault500 (never leak stack traces)
Upstream dependency failed or timed out502 / 504
Planned unavailability, overload503 with Retry-After

Hard rule: never return 200 with {"success": false}. Status codes drive client retries, caches, proxies and monitoring.

4. Bodies and errors

  • Return the resource representation directly; avoid { "data": ... } envelopes unless the API already uses them. Collections are the exception: they need room for paging metadata, so use { "data": [...], "next_cursor": "..." } or the existing equivalent.
  • Timestamps: RFC 3339 in UTC with Z (2026-03-01T12:00:00Z). Money: integer minor units plus currency code ({"amount": 1999, "currency": "EUR"}), never floats.
  • Enums are strings, documented as open sets: clients must tolerate unknown values.
  • Omit vs null: pick one rule for absent optional fields and apply it everywhere.
  • Error body: use RFC 9457 application/problem+json unless the API already has a shape. Always include a stable machine-readable code and per-field errors for validation:
{
  "type": "https://api.example.com/problems/validation",
  "title": "Request body failed validation",
  "status": 422,
  "detail": "2 fields are invalid",
  "errors": [
    { "pointer": "/email", "code": "invalid_format", "detail": "must be an email address" },
    { "pointer": "/quantity", "code": "out_of_range", "detail": "must be between 1 and 100" }
  ],
  "request_id": "req_01J8Z..."
}

5. Query conventions

  • Filtering: plain equality params for common fields (?status=open&customer_id=cus_1); for ranges use suffixed params (created_after, created_before) or bracket syntax (created[gte]=). Do not accept arbitrary field names that map straight to SQL columns.
  • Multi-value: repeated params (?status=open&status=paid) or comma lists; pick one.
  • Sorting: ?sort=-created_at,name (leading - is descending). Whitelist sortable fields and always append a unique tiebreaker server-side.
  • Sparse fields / expansion: ?fields=id,total and ?expand=customer only if clients need them; each expansion is a performance commitment.
  • Reject unknown filter params with 400 rather than silently ignoring them; silent ignores turn typos into “return everything”.
  • Pagination details live in the api-pagination skill; default page size 20-50, hard max.

6. Concurrency, async and retries

  • Optimistic concurrency: return ETag on GET, require If-Match on PUT/PATCH/DELETE for contended resources, answer 412 on mismatch.
  • PATCH: use JSON Merge Patch (RFC 7396, application/merge-patch+json) by default; null means “remove”. Use JSON Patch (RFC 6902) only when clients need array ops.
  • Long-running work: respond 202 Accepted with Location: /operations/{id}; the operation resource exposes status (pending|running|succeeded|failed), a result link and an error. Do not hold HTTP connections open for minutes.
  • Unsafe POSTs that clients retry (payments, orders) need an Idempotency-Key.

7. Contract and tests

  • Update or create the OpenAPI document in the same change as the handler.
  • Add at least one test per endpoint for: success shape, auth failure, validation failure, not found. Assert status, Content-Type, and error code, not message text.

Gotchas

  • PUT that silently ignores missing fields is a PATCH; clients will rely on the bug.
  • Returning 404 for “collection is empty” breaks clients; an empty list is 200.
  • Booleans that later need a third state (is_active) become breaking changes; prefer a status enum for lifecycle fields.
  • Case-sensitive IDs combined with case-insensitive routing produce phantom 404s.
  • Large integers (IDs, money in minor units over 2^53) lose precision in JavaScript clients; send them as strings.
  • DELETE with a request body is ignored by some proxies; put parameters in the path.
  • CORS preflights fail on non-simple custom headers unless allowed; see cors-configuration.

Verification

  • Run the project’s API tests; then exercise each new endpoint with curl -i and confirm status, headers (Location, ETag, Content-Type) and body shape.
  • Diff the OpenAPI spec against the base branch and confirm no unintended breaking change (removed field, narrowed type, new required param).
  • Grep the handlers for res.status(200) / return 200 paths that wrap errors.

Output template

When proposing or reviewing an API, deliver:

## Endpoint summary
| Method | Path | Purpose | Success | Errors |
|---|---|---|---|---|
| POST | /invoices | Create draft invoice | 201 + Location | 400, 409, 422 |

## Conventions applied
- Casing, IDs, timestamps, money, error format, pagination: <one line each>

## Breaking-change check
- <none | list with migration notes>

## Open questions
- <decisions the API owner must make>

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "REST API Design"
  short_description: "Endpoints clients can predict before reading docs"
  default_prompt: "$rest-api-design Design the endpoints for invoices and line items in this service"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem