# 402 Payment Required

> Reserved for future use in digital payment systems. Learn about this experimental status code and modern payment verification alternatives.

Source: https://howhttpworks.com/status-codes/402
Last reviewed: 2026-10-04

> **TL;DR:** Reserved for future digital payments, rarely used in practice. Most sites use 403 Forbidden with payment info instead.

## What is 402 Payment Required?

A **402 Payment Required** status code is reserved for future use in digital payment systems. Think of it like a "No Entry Without Ticket" sign—the resource exists, but you need to pay before accessing it. However, this code was never standardized and is rarely used in practice.

While originally intended for digital cash or micropayment systems, modern implementations typically use 401 (Unauthorized) or 403 (Forbidden) with custom payment logic instead.

## When Does This Happen?

Although not standardized, you might theoretically see a 402 Payment Required response in:

**1. Paywalled Content**

```text
Article behind paywall
/premium-article → 402 Payment Required
```

**2. API Rate Limit Exceeded (Paid Tier)**

```text
Free tier exhausted, payment required
/api/data → 402 Payment Required → Upgrade to continue
```

**3. Subscription Services**

```text
Subscription expired
/members-only-content → 402 Payment Required
```

**4. Metered API Usage**

```text
Credits depleted, payment required to continue
/api/translate → 402 Payment Required → Add credits
```

**5. Digital Goods Purchase**

```text
Download requires payment
/download/ebook → 402 Payment Required
```

## Example Responses

**Paywalled Article:**

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
WWW-Authenticate: Bearer realm="premium-content"
X-Payment-Required: subscription
Link: <https://example.com/subscribe>; rel="payment"

{
  "error": "Payment Required",
  "message": "This content requires an active subscription",
  "subscription_url": "https://example.com/subscribe",
  "plans": [
    {
      "name": "Monthly",
      "price": "$9.99/month",
      "url": "https://example.com/subscribe/monthly"
    },
    {
      "name": "Annual",
      "price": "$99/year",
      "url": "https://example.com/subscribe/annual"
    }
  ]
}
```

**API Credit Depletion:**

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
X-RateLimit-Remaining: 0
X-Credits-Required: 100
Retry-After: 3600

{
  "error": "Insufficient Credits",
  "message": "You have exhausted your API credits",
  "credits_required": 100,
  "current_balance": 0,
  "purchase_url": "https://api.example.com/credits/purchase"
}
```

**Subscription Expired:**

```http
HTTP/1.1 402 Payment Required
Content-Type: text/html
X-Subscription-Status: expired
X-Subscription-Expired: 2026-01-01

<!DOCTYPE html>
<html>
<head><title>Subscription Required</title></head>
<body>
<h1>Subscription Expired</h1>
<p>Your subscription expired on January 1, 2026.</p>
<p><a href="/renew">Renew Subscription</a></p>
</body>
</html>
```

## Real-World Example

Imagine you're trying to access premium API features without sufficient credits:

**Client API Request:**

```http
GET /api/v1/premium/analytics HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Accept: application/json
```

**402 Payment Required Response:**

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
WWW-Authenticate: Bearer realm="premium-api", error="insufficient_credits"
X-Credits-Required: 500
X-Current-Balance: 0
Link: <https://api.example.com/billing/purchase>; rel="payment"

{
  "status": 402,
  "error": "Payment Required",
  "message": "Insufficient credits for premium analytics endpoint",
  "details": {
    "credits_required": 500,
    "current_balance": 0,
    "credits_needed": 500
  },
  "actions": {
    "purchase_credits": {
      "url": "https://api.example.com/billing/purchase",
      "method": "POST",
      "packages": [
        {"credits": 1000, "price": "$10.00", "id": "pkg_1k"},
        {"credits": 5000, "price": "$40.00", "id": "pkg_5k"},
        {"credits": 10000, "price": "$75.00", "id": "pkg_10k"}
      ]
    },
    "upgrade_plan": {
      "url": "https://api.example.com/billing/upgrade",
      "method": "POST",
      "plans": [
        {"name": "Pro", "monthly_credits": 10000, "price": "$49/month"},
        {"name": "Enterprise", "monthly_credits": 100000, "price": "$299/month"}
      ]
    }
  }
}
```

## 402 vs Other Authorization Codes

| Code    | Meaning          | Authentication | Payment  | Use Case                    |
| ------- | ---------------- | -------------- | -------- | --------------------------- |
| **402** | Payment required | Optional       | Required | Digital payments (rare)     |
| **401** | Unauthorized     | Required       | N/A      | Missing/invalid credentials |
| **403** | Forbidden        | Authenticated  | N/A      | Insufficient permissions    |
| **451** | Legal reasons    | N/A            | N/A      | Censored/blocked content    |

## Important Characteristics

**Reserved Status:**

```text
- 402 is officially "Reserved for future use"
- Not standardized in HTTP specification
- No widely accepted implementation
- Most systems use 401 or 403 instead
```

**Modern Alternatives:**

```http
# Most common: Use 403 with payment info
HTTP/1.1 403 Forbidden
X-Payment-Required: true
Content-Type: application/json

{
  "error": "payment_required",
  "payment_url": "/subscribe"
}
```

## Common Mistakes

**❌ Using 402 when 401 or 403 is more appropriate**

```http
HTTP/1.1 402 Payment Required  ← Non-standard, confusing
Location: /subscribe

# Better:
HTTP/1.1 403 Forbidden
X-Reason: subscription_required
Location: /subscribe
```

**❌ Not providing payment information**

```http
HTTP/1.1 402 Payment Required  ← No info on how to pay
Content-Type: text/plain

Payment required.  ← Unhelpful
```

**❌ Using for authentication instead of payment**

```http
HTTP/1.1 402 Payment Required  ← Wrong code
WWW-Authenticate: Bearer

# Should be:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer
```

**✅ If using 402, provide clear payment info**

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
Link: <https://example.com/subscribe>; rel="payment"

{
  "error": "payment_required",
  "payment_url": "https://example.com/subscribe",
  "message": "Subscription required to access this content"
}
```

## Getting 402 Payment Required right

**Consider Using 403 Instead:**

```http
HTTP/1.1 403 Forbidden
Content-Type: application/json
X-Reason: payment_required

{
  "error": "subscription_required",
  "message": "Active subscription needed",
  "subscribe_url": "/subscribe"
}
```

**If Using 402, Be Descriptive:**

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
Link: <https://api.example.com/pricing>; rel="payment"

{
  "error": "Payment Required",
  "message": "This API endpoint requires a paid plan",
  "current_plan": "free",
  "required_plan": "pro",
  "upgrade_url": "https://api.example.com/upgrade",
  "pricing": {
    "pro": "$49/month",
    "enterprise": "$299/month"
  }
}
```

**Include Clear Call-to-Action:**

```html
<!DOCTYPE html>
<html>
  <head>
    <title>Premium Content</title>
  </head>
  <body>
    <h1>Premium Content</h1>
    <p>This article is available to subscribers only.</p>
    <a href="/subscribe" class="cta-button">Subscribe Now</a>
    <p>Plans starting at $9.99/month</p>
  </body>
</html>
```

**Provide Machine-Readable Payment Info:**

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
Link: <https://example.com/api/subscribe>; rel="payment"

{
  "error": "payment_required",
  "error_description": "Insufficient account balance",
  "payment_methods": ["credit_card", "paypal", "stripe"],
  "minimum_payment": 10.00,
  "currency": "USD",
  "payment_endpoint": "/api/payments"
}
```

## Modern Payment Verification Patterns

**Subscription Check (Recommended):**

```javascript
app.get('/premium/content', checkSubscription, (req, res) => {
  if (!req.user.hasActiveSubscription) {
    return res.status(403).json({
      error: 'subscription_required',
      message: 'Active subscription needed',
      subscribe_url: '/subscribe'
    })
  }

  res.json({ content: 'Premium content here' })
})
```

**API Credits System:**

```javascript
app.get('/api/premium-feature', async (req, res) => {
  const credits = await getCreditsBalance(req.user.id)

  if (credits < REQUIRED_CREDITS) {
    return res.status(403).json({
      error: 'insufficient_credits',
      required: REQUIRED_CREDITS,
      current: credits,
      purchase_url: '/credits/buy'
    })
  }

  await deductCredits(req.user.id, REQUIRED_CREDITS)
  res.json({ data: premiumData })
})
```

## Implementation Examples

**Express.js (Using 403 instead):**

```javascript
app.get('/premium/article', authenticateUser, (req, res) => {
  if (!req.user.isPremium) {
    return res.status(403).header('X-Payment-Required', 'true').json({
      error: 'payment_required',
      message: 'Premium subscription required',
      subscribe_url: '/subscribe',
      plans: getPricingPlans()
    })
  }

  res.json({ article: getPremiumArticle() })
})
```

**Django:**

```python
from django.http import JsonResponse

def premium_content(request):
    if not request.user.has_active_subscription():
        return JsonResponse({
            'error': 'payment_required',
            'message': 'Active subscription required',
            'subscribe_url': '/subscribe'
        }, status=403)  # Using 403, not 402

    return JsonResponse({'content': get_premium_content()})
```

**API Gateway Pattern:**

```javascript
// Cloudflare Worker or similar
async function handleRequest(request) {
  const apiKey = request.headers.get('X-API-Key')
  const usage = await checkUsage(apiKey)

  if (usage.credits <= 0) {
    return new Response(
      JSON.stringify({
        error: 'credits_exhausted',
        message: 'Please purchase more credits',
        purchase_url: 'https://example.com/credits'
      }),
      {
        status: 403, // Using 403 instead of 402
        headers: { 'Content-Type': 'application/json' }
      }
    )
  }

  return fetch(request)
}
```

## Try It Yourself

Visit our [request builder](https://howhttpworks.com/tools/playground) to simulate payment-required scenarios:

1. Set method to **GET**
2. Set path to **/premium/content**
3. Try without subscription header
4. See 403 response with payment info
5. Add subscription header and retry

## Try it with curl

`402 Payment Required` is reserved by RFC 9110 and has no standard behavior, so there is no generic request that triggers it. A few paid APIs return it for exhausted plans or missing payment; the details live in their own docs. To see what one sends, read the headers and body.

```bash
curl -i https://api.example.com/v1/premium-endpoint
```

## Related Status Codes

- [401 Unauthorized](https://howhttpworks.com/status-codes/401) - Authentication required
- [403 Forbidden](https://howhttpworks.com/status-codes/403) - Insufficient permissions (commonly used for payment)
- [429 Too Many Requests](https://howhttpworks.com/status-codes/429) - Rate limit exceeded
- [451 Unavailable For Legal Reasons](https://howhttpworks.com/status-codes/451) - Legally blocked content
