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

# Request Lifecycle & Statuses

> Understand HTTPayer request states, payments, and refunds

## Request Lifecycle Overview

Every HTTPayer request progresses through a defined lifecycle, especially when payments or refunds are involved.

The lifecycle is divided into five phases:

1. Discovery
2. Payment Processing
3. Upstream Execution
4. Completion
5. Refund Handling (if applicable)

## Status Reference

HTTPayer uses two layers of status values. See the [Status System](/api/status-system) reference for a full explanation of the mapping between them.

### Sync-Response Statuses

These appear in the `X-HTTPayer-Status` response header and `httpayerStatus` field on synchronous responses. They are **not** stored in the webhooks database.

| Status               | Description                                   |
| -------------------- | --------------------------------------------- |
| `payment_required`   | Client must submit a valid x402 payment (402) |
| `payment_validating` | On-chain confirmation in progress             |
| `processing`         | Upstream API call in flight                   |

### Async / Webhook Statuses

These are stored in the database and returned by `GET /webhooks/:id`. An initial `async_processing` record is created when background polling is launched (e.g., after a proxy 502 with `webhook_id`); it transitions to one of the terminal states below.

#### In-Flight

| Status             | Webhook response | Description                                            |
| ------------------ | ---------------- | ------------------------------------------------------ |
| `async_processing` | `pending`        | Background polling active; monitoring payment on-chain |

#### Terminal — Success

| Status             | Webhook response   | Description                                                     |
| ------------------ | ------------------ | --------------------------------------------------------------- |
| `success`          | `success`          | Request completed, upstream responded 2xx                       |
| `success_refunded` | `success_refunded` | Request succeeded; refund issued (target did not charge)        |
| `refund_confirmed` | `refund_confirmed` | Refund transaction confirmed on-chain                           |
| `no_refund_needed` | `no_refund_needed` | Target charged HTTPayer within the auth window — refund skipped |

#### Terminal — Failure

| Status              | Webhook response | Description                                        |
| ------------------- | ---------------- | -------------------------------------------------- |
| `payment_failed`    | `failed`         | User payment never settled on-chain                |
| `upstream_error`    | `failed`         | Target API returned a 5xx error                    |
| `internal_error`    | `failed`         | HTTPayer-side error                                |
| `rate_limited`      | `failed`         | Account daily\_limit exceeded                      |
| `validation_failed` | `failed`         | Invalid request parameters                         |
| `refund_failed`     | `failed`         | Refund attempt failed (manual intervention needed) |

## Upstream Execution

### Proxy: upstream payment refused (502)

When the target API returns 402 after all sync retries, HTTPayer returns `502 Bad Gateway` with `message: "Upstream API refused payment after N attempts"`. If blockchain polling is active, a `webhook_id` field is included in the response body — use `GET /webhooks/:id` to track whether the payment eventually confirmed on-chain. If confirmed, credits are charged; if not, reserved credits are automatically refunded.

### SSRF protection (400)

The `api_url` field is validated before any outbound request is made. Requests targeting private, loopback, or link-local addresses are rejected with `400 Bad Request`. Blocked ranges include:

* Loopback: `127.0.0.0/8`, `::1`
* Link-local / cloud metadata: `169.254.0.0/16`
* Private: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`
* Unspecified: `0.0.0.0`, `::`

Non-`http`/`https` schemes (e.g. `file://`, `ftp://`) are also rejected.

### Refund deduplication

If a refund has already been issued for a relay transaction (status `confirmed` or `pending`), any subsequent refund attempt for the same transaction is a no-op — the original refund hash is returned immediately without executing a new blockchain transaction. This prevents double-refunds from retries or concurrent error paths.

## Where Statuses Appear

| Surface                          | Status type          | Field / Header             |
| -------------------------------- | -------------------- | -------------------------- |
| Synchronous 2xx/4xx/5xx response | Sync-response status | `X-HTTPayer-Status` header |
| Synchronous JSON response body   | Sync-response status | `httpayerStatus` field     |
| `GET /webhooks/:id` (202)        | `pending`            | `status` field             |
| `GET /webhooks/:id` (200)        | success variant      | `status` field             |
| `GET /webhooks/:id` (500)        | `failed`             | `status` field             |

> For async flows and refunds, see the [Webhooks](/api/webhooks/get-refund-status) documentation.
