> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shouldertap.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Status codes and reason codes

> HTTP status codes the ShoulderTap API returns, and the reason codes carried on a failed request.

The ShoulderTap API uses standard HTTP status codes. Separately, a request that can't be answered fails with a machine-readable **reason code** delivered to the consumer.

## HTTP status codes

| Status                | Meaning                                                                               |
| --------------------- | ------------------------------------------------------------------------------------- |
| `200 OK`              | The request succeeded.                                                                |
| `201 Created`         | A consumer was registered (`POST /consumers`).                                        |
| `204 No Content`      | A consumer was unregistered (`DELETE /consumers/{id}`).                               |
| `401 Unauthorized`    | The bearer token was missing or incorrect. See [Authentication](/api/authentication). |
| `404 Not Found`       | The referenced request, proposal, or consumer doesn't exist.                          |
| `501 Not Implemented` | `POST /slack/events` was called but no Slack transport is configured.                 |

## Reason codes

When a request fails outright, the `on_request_failed` event (delivered to the consumer) carries a `reason` with exactly one of these codes:

<ResponseField name="timeout">
  No expert replied anywhere within `give_up_after` (default 24 hours).
</ResponseField>

<ResponseField name="no_expert_found">
  Routing found no expert for the request's topic — no exact match, no fuzzy match, and no fallback.
</ResponseField>

<ResponseField name="expert_declined">
  The expert declined to answer.
</ResponseField>

<ResponseField name="rate_limited">
  Every candidate expert was at their rate-limit cap and the request could not be placed.
</ResponseField>

<ResponseField name="cancelled">
  The request was cancelled before it resolved.
</ResponseField>

<ResponseField name="error">
  An unexpected error prevented the request from being processed.
</ResponseField>

## Request status vs. submit status

A request's lifecycle status progresses through `queued → asked → escalated → proposed → accepted | rejected | failed` — read it from `GET /requests/{id}`.

Separately, the status returned at **submit** time by `POST /requests` reflects whether deduplication kicked in:

<ResponseField name="queued">
  A new request was accepted and routed.
</ResponseField>

<ResponseField name="deduped_open">
  The request matched an open request with the same `dedup_key`; the consumer was attached as a subscriber. No new ask.
</ResponseField>

<ResponseField name="deduped_resolved">
  The request matched an already-accepted request; the existing proposal is delivered immediately.
</ResponseField>

<ResponseField name="failed">
  The request could not be routed (see the reason codes above).
</ResponseField>
