nsip 0.7.1

NSIP Search API client for nsipsearch.nsip.org/api
Documentation
# `api/error` — Upstream API returned an error

- **type**: `https://github.com/zircote/nsip/blob/main/docs/reference/errors/api/error.md`
- **status**: the upstream HTTP status (e.g. 400, 429, 500)
- **exit_code**: `1` for a 4xx client error; `75` (`EX_TEMPFAIL`) for `429` and `5xx`
- **class**: caller (4xx) or transient (429 / 5xx)
- **`suggested_fix` applicability**: `unspecified` for 429/5xx; none for other 4xx
- **`retry_after`**: present for `429` (and `5xx` when the upstream sends `Retry-After`)

## When it occurs

The NSIP API returned a non-success, non-404 HTTP status. The `status` member
carries the real upstream code so a consumer can branch:

- **4xx (not 429)** — a client-side problem (bad request the API rejected).
  Terminal; exit `1`.
- **429** — rate limited. Transient; exit `75`; `retry_after` carries the
  delay parsed from the `Retry-After` header.
- **5xx** — upstream server error. Transient; exit `75`. The client already
  retried retryable 5xx (`500/502/503/504`) with backoff before surfacing this.

## Recovery

For 429/5xx, wait `retry_after` seconds (or use exponential backoff) and retry.
For other 4xx, inspect `detail` (the upstream response body) — the request
itself needs to change.

## Example

```json
{
  "type": "https://github.com/zircote/nsip/blob/main/docs/reference/errors/api/error.md",
  "title": "Upstream API returned an error",
  "status": 429,
  "detail": "API error (HTTP 429): rate limited",
  "instance": "urn:nsip:search:b8a9c0f3-f8fc-44a0-8c9c-f9dc78b1b7c2",
  "exit_code": 75,
  "suggested_fix": "wait for the retry_after interval before retrying",
  "retry_after": 30,
  "docs_url": "https://github.com/zircote/nsip/blob/main/docs/reference/errors/api/error.md"
}
```