# Error Semantics

Every API error returns a structured JSON body with a machine-readable code and a human-readable message. Parse both fields to determine the failure class and appropriate recovery action.

## HTTP Error Classes

| Status | Meaning | Common Causes |
|--------|---------|---------------|
| `400` | Bad Request | Invalid payload, missing required fields, malformed attachment metadata |
| `401` | Unauthorized | Missing or expired authentication credentials |
| `402` | Payment Required | Paid mutation attempted without a valid payment header |
| `403` | Forbidden | Ownership mismatch -- caller is not the authorized party for this resource |
| `404` | Not Found | Resource does not exist or has been deleted |
| `409` | Conflict | Invalid state transition (e.g., accepting an already-settled contract) |

## Error Response Format

All errors follow a consistent JSON structure:

```json
{
  "code": "invalid_transition",
  "message": "Contract is in 'delivered' state and cannot be accepted"
}
```

## Business Error Patterns

### Payment errors (`402`)

Returned when a mutation requires payment. Include one of the following headers on retry:

- `X-Webcash-Secret` -- a valid Webcash secret covering the required fee
- `X-Bitcoin-Secret` -- a valid Bitcoin payment secret

When using the `hrmw` CLI, payment is handled automatically on `402` responses.

### State conflict errors (`409`)

Indicates an invalid transition in a stateful resource (contracts, witnesses). To recover:

1. Fetch the current resource state
2. Verify the transition is valid from the current state
3. Confirm the caller is the correct party (buyer vs. seller) for the action

### Authorization errors (`401` / `403`)

- **`401`** -- re-authenticate and retry
- **`403`** -- verify the caller's fingerprint matches the expected party for the resource

## Recovery Best Practices

- Always parse the `code` field for programmatic branching -- do not match on `message` text
- On `402`, read the required fee from the error body or from `GET /api/fees`, then retry with payment
- On `409`, re-fetch the resource to get its current state before deciding the next action
- On `400`, inspect the `message` for field-level details and correct the payload

## Related

- [Fees](/reference/fees) -- dynamic fee schedule and paid action list
- [OpenAPI Reference](/reference/openapi) -- full response schemas per endpoint
- [Troubleshooting Contracts](/troubleshooting/contracts) -- resolving contract transition errors
