Blog
Wild & Free Tools

UUID in REST API Design — Best Practices

Last updated: January 2026 6 min read
Quick Answer

Table of Contents

  1. UUID in URL Path Parameters
  2. Idempotency Keys with UUID
  3. Correlating Requests — Trace IDs
  4. Common UUID API Design Mistakes
  5. UUID in API Response Bodies
  6. Frequently Asked Questions

UUIDs in API design solve a specific problem: auto-increment integer IDs leak information. A URL like /orders/4521 tells the caller your application has roughly 4,521 orders and that order 4,520 exists. UUID-based URLs like /orders/550e8400-e29b-41d4-a716-446655440000 reveal nothing. This guide covers the right patterns — and the common mistakes that erode these benefits.

UUID in URL Path Parameters

The standard pattern:

GET  /orders/{uuid}          → fetch a single order
PUT  /orders/{uuid}          → replace an order
PATCH /orders/{uuid}         → update fields on an order
DELETE /orders/{uuid}        → delete an order
GET  /orders/{uuid}/items    → nested resources

// Example:
GET /orders/550e8400-e29b-41d4-a716-446655440000
GET /orders/550e8400-e29b-41d4-a716-446655440000/items/a6edc906-2f9f-5fb2-a373-efac406f0ef2

Validation rules:

Idempotency Keys — UUID for Safe Retries

Idempotency keys prevent duplicate operations when POST requests are retried (network timeout, client retry logic). The pattern: client generates a UUID before the first attempt, sends it as a header. If the server has already processed this key, it returns the original response instead of creating a duplicate.

// Client sends:
POST /orders
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{"productId": "...", "quantity": 1}

// Server logic (pseudocode):
idempotencyKey = request.headers["Idempotency-Key"]
if (idempotencyKey):
    cached = cache.get(idempotencyKey)
    if (cached):
        return cached.response  // Return original response, don't re-create

result = createOrder(request.body)
cache.set(idempotencyKey, result, ttl=24h)
return result

Stripe, PayPal, and most financial APIs use this pattern. The UUID is generated client-side because the client is responsible for ensuring uniqueness per attempt. Store idempotency keys in Redis or a database with a TTL of 24 hours.

Sell Custom Apparel — We Handle Printing & Free Shipping

UUID for Request Correlation and Tracing

// Generate a trace ID per request:
GET /orders/550e8400-...
X-Request-ID: a6edc906-2f9f-5fb2-a373-efac406f0ef2

// Server propagates to downstream services:
X-Request-ID: a6edc906-2f9f-5fb2-a373-efac406f0ef2  // same ID throughout

// Log every service with the same trace ID:
{"level":"info","trace_id":"a6edc906-...","message":"order fetch started"}

// If client does not send one, generate at the API gateway:
if (!req.headers["x-request-id"]) {
    req.headers["x-request-id"] = crypto.randomUUID();
}

Correlation IDs turn scattered logs from multiple services into a traceable request chain. Always echo the request ID back in the response headers so clients can include it in bug reports.

Common Mistakes When Using UUID in APIs

Exposing both integer ID and UUID in the response:

// Bad — leaks your internal integer ID:
{"id": "550e8400-...", "internal_id": 4521, "status": "pending"}

// Good — UUID only in external-facing response:
{"id": "550e8400-...", "status": "pending"}

Not validating format before querying:

// Bad — can produce a 500 error from the database:
const order = await db.findById(req.params.id); // raw string passed to DB

// Good — validate first:
let id;
try { id = UUID.fromString(req.params.id); }
catch (e) { return res.status(400).json({error: "Invalid ID format"}); }
const order = await db.findById(id);

Using UUID as a slug in user-facing URLs: UUIDs are 36 characters — difficult to copy, ugly in emails, and impossible to remember. For URLs shared with users, consider a slug (/orders/my-gym-order-march) alongside the internal UUID, or use a shorter identifier like NanoID for the public-facing URL while keeping UUID internally.

UUID in API Response Bodies

Standard conventions for UUID fields in JSON responses:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",     // always string, always hyphenated
  "orderId": "a6edc906-2f9f-5fb2-a373-efac406f0ef2", // camelCase for related IDs
  "createdAt": "2026-04-14T12:00:00Z"
}

Conventions:

Generate UUIDs for API Testing

The Cheetah UUID Generator produces 1 or 10 RFC-compliant UUID v4 values — paste into request bodies, headers, or Postman data files instantly.

Open Free UUID Generator

Frequently Asked Questions

Should REST API resource IDs be UUIDs or integers?

UUIDs for most cases. They prevent sequential enumeration attacks, work naturally in distributed systems, and can be generated client-side before the resource is created. Integers are fine for internal-only APIs or when ID density is critical.

What HTTP status code for an invalid UUID in a path parameter?

400 Bad Request — the client sent a malformed identifier. Do not return 404 for format errors, as 404 implies "valid format but not found." A clear 400 error body like {"error": "Invalid ID format"} is most helpful.

Can the client generate the UUID for a POST request?

Yes — this is a valid pattern (sometimes called "client-generated IDs"). The client generates a UUID, uses it as the resource ID in the URL: PUT /orders/{uuid} instead of POST /orders. This makes the operation inherently idempotent.

What is the difference between an idempotency key and a request ID?

An idempotency key is tied to a business operation — it prevents duplicate order creation. A request ID (trace ID) is for observability — it correlates log entries across services. Both are UUIDs, but they serve different purposes and are stored differently.

Should I expose UUID or a shorter ID in public-facing URLs?

Depends on the context. For API calls (machine-to-machine), UUID is fine. For URLs shared with humans (emails, dashboards, support tickets), consider a shorter URL-safe ID like NanoID (21 chars) or a readable slug alongside the UUID.

Kevin Harris
Kevin Harris Finance & Calculator Writer

Kevin is a certified financial planner passionate about making financial literacy tools free and accessible.

More articles by Kevin →
Launch Your Own Clothing Brand — No Inventory, No Risk