Error Handling
The middleware throws an IdempotencyException (which returns a 400 Bad Request) in three scenarios.
Invalid Idempotency Key
The key must be a valid UUID v4. Any other format is rejected:
POST /api/orders HTTP/1.1
Idempotency-Key: not-a-valid-uuid
→ 400 Bad Request
Key Reused with Different Body
If a client sends the same idempotency key but with a different request body, the middleware rejects it. This prevents accidental key collisions:
# First request
POST /api/orders
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
{"product_id": 1, "quantity": 2}
→ 201 Created
# Same key, different body
POST /api/orders
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
{"product_id": 5, "quantity": 1}
→ 400 Bad Request
Key Reused on Different Endpoint
Similarly, using the same key on a different endpoint is rejected:
# First request
POST /api/orders
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
→ 201 Created
# Same key, different endpoint
POST /api/payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
→ 400 Bad Request
Validation Errors Are Not Cached
Responses with a 422 Unprocessable Entity status are intentionally excluded from caching. This means if a request fails validation, the client can fix the data and retry with the same idempotency key without getting the cached error response.
Handling the Exception
The IdempotencyException extends Symfony's HttpException with a 400 status code. If you're using the API Toolkit package, exceptions are automatically rendered as JSON:API errors. Otherwise, Laravel's default exception handler will return a standard error response.