# 429: Credit Limit Reached

A `429 TOO MANY REQUESTS` can be returned for two different reasons:

- Credit limit reached
- Too many concurrent requests

This page is only for the **credit limit** case. If your issue is concurrency, use [429: Too Many Concurrent Requests](https://www.marketdata.app/docs/api/troubleshooting/too-many-concurrent-requests).

For full policy details, see [Rate Limits](https://www.marketdata.app/docs/api/rate-limiting).

## Fast Triage

Use the response message and headers to identify which 429 you hit.

Typical credit-limit error payload:

```json
{
  "s": "error",
  "errmsg": "API credit limit reached for current window.",
  "troubleshootingGuide": "https://www.marketdata.app/docs/api/troubleshooting/running-out-of-credits"
}
```

**Credit-limit 429 indicators:**
- Error message indicates credit/rate budget exhaustion for your plan window
- `X-Api-Ratelimit-Remaining` is `0` (or effectively exhausted)

**Concurrency 429 indicators:**
- Error message indicates too many simultaneous requests
- Usually occurs during bursts with many in-flight requests
- Official SDKs handle concurrency automatically and maximize throughput up to the 50-request limit without exceeding it

## 30-Second Action Checklist

1. Confirm this is a credit-limit 429 (not concurrency).
2. Read `X-Api-Ratelimit-Remaining` and `X-Api-Ratelimit-Reset`.
3. Find your plan group below and apply its primary workflow.
4. Check `X-Api-Ratelimit-Consumed` on recent heavy requests.
5. If still blocked repeatedly after optimization, escalate (support or plan change).

## Plan Groups

Troubleshooting should follow your plan's optimization capabilities.

| Plan Group       | Plans                                     | Limit Window | `mode=cached` Available |
|------------------|-------------------------------------------|--------------|-------------------------|
| Free + Trials    | Free Forever, Starter Trial, Trader Trial | Daily        | No                      |
| Starter + Trader | Starter, Trader                           | Daily        | Yes                     |
| Quant + Prime    | Quant, Prime                              | Per-minute   | Yes                     |

> [!WARNING]
> **Trial plan limitation**
>
> `mode=cached` is **not available** on Starter Trial and Trader Trial.

> [!CAUTION]
> **Reset Window Gotcha (All Daily-Reset Plans)**
>
> All plans with daily credit windows (Free Forever, Starter Trial, Trader Trial, Starter, Trader) reset at **9:30 AM Eastern Time**, not midnight.
>
> This is intentional safety behavior: if a script runs out of control overnight, the reset timing limits impact to one trading day budget instead of potentially consuming two trading-day budgets across a midnight boundary.

## Plan Playbooks

### Free Forever + Trial Plans (No Cached Mode)

These plans cannot use cached mode. For bulk option use, use one of these workflows:

1. **One-step server-side filtering:** keep quote columns and aggressively reduce contracts on the chain request using filters such as `strikeLimit`, `expiration`, `type`, `strike`, `minBid`, and `maxBid`.
2. **Two-step local filtering:** pull the full/large chain without quote columns, apply your own logic locally, then request quotes only for selected contracts using `options/quotes`.

If current-day quote freshness is not required, a third strategy can be cheaper: use **historical option chains** with the `date` parameter. Historical chains are billed at **1 credit per 1,000 option symbols**, while real-time/15-minute delayed quote chains are billed per symbol.

```http
# One-step: server-side liquidity + contract filters (quotes included)
GET https://api.marketdata.app/v1/options/chain/UNDERLYING/?expiration=YYYY-MM-DD&type=call&strikeLimit=5&minBid=0.50&maxBid=10&columns=symbol,strike,expiration,type,bid,ask,mid,last,openInterest,volume

# Two-step (Step 1): broad chain without costly quote columns
GET https://api.marketdata.app/v1/options/chain/UNDERLYING/?expiration=all&columns=symbol,strike,expiration,type,openInterest,volume

# Two-step (Step 2): quotes only for selected contracts
GET https://api.marketdata.app/v1/options/quotes/OPTION_SYMBOL/

# Historical chain example (lower-cost bulk snapshot)
GET https://api.marketdata.app/v1/options/chain/UNDERLYING/?date=YYYY-MM-DD&expiration=all
```

If you are still getting credit-limit 429 after these optimizations, the primary path is to upgrade to a paid plan.

### Starter + Trader (Daily Limits + Cached Mode)

Primary optimization for this plan group is `mode=cached` on bulk requests.

Recommended process:

1. Request bulk data with `mode=cached` (optionally with `maxage`).
2. Inspect the `updated` field in the response to measure snapshot age.
3. If fresh enough, use cached data.
4. If too old, re-request only required contracts/symbols in live mode instead of re-pulling the full chain.

```http
# Step 1: bulk chain from cache (cheap, 1 credit)
GET https://api.marketdata.app/v1/options/chain/UNDERLYING/?mode=cached&maxage=5min&expiration=YYYY-MM-DD

# Step 2: only if selected contracts are too stale per `updated`, request live quotes for those contracts
GET https://api.marketdata.app/v1/options/quotes/OPTION_SYMBOL/
```

Additional controls for Starter + Trader:

1. Filter option chains aggressively (`strikeLimit`, `expiration`, `type`, `strike`, liquidity filters).
2. Exclude `bid`, `ask`, `mid`, `last` when current pricing is not needed.
3. Add daily credit guardrails to avoid getting blocked for the rest of the day.

### Quant + Prime (Per-Minute Limits + Cached Mode)

Use cached-mode bulk strategy and filter optimization, plus minute-window pacing:

1. Smooth burst traffic (queue + worker pool)
2. Pace large chain pulls across the minute window
3. Prefer cached mode for full-chain or broad bulk pulls

Quant/Prime have no daily credit cap. 429s here are the result of per-minute bursts, not daily depletion.

## How Pricing Actually Works

The mental model `1 request = 1 credit` is often wrong for bulk and candles workloads.

### Common baseline
- Many non-bulk responses: `1 request = 1 credit`

### High-usage endpoints where pricing scales

1. `options/chain`
   - Real-time or delayed quote chains can consume per option symbol returned when quote fields are included.
   - Historical chain requests (`date` parameter) are billed at 1 credit per 1,000 option symbols.
2. `stocks/quotes`
   - Multi-symbol quote responses with quote fields can consume per symbol returned.
3. `stocks/prices`
   - Multi-symbol price/quote responses with quote fields can consume per symbol returned.
4. `stocks/bulkcandles`
   - Bulk candle responses can consume per symbol returned.
5. `stocks/candles`
   - Candle responses are billed at 1 credit per 1,000 candles, so large ranges can consume multiple credits in one request.

Practical rule: credit usage scales with response size on bulk quote endpoints and long candle responses.

### High-impact example

```http
# Full live chain can consume very large credits
GET https://api.marketdata.app/v1/options/chain/UNDERLYING/?expiration=all

# Filtered chain reduces returned symbols
GET https://api.marketdata.app/v1/options/chain/UNDERLYING/?expiration=all&strikeLimit=1

# Cached mode (paid plans only) reduces credits to 1
GET https://api.marketdata.app/v1/options/chain/UNDERLYING/?mode=cached
```

For cached mode details, see [mode parameter](https://www.marketdata.app/docs/api/universal-parameters/mode).

## Diagnose With Headers

Check these headers on every response:

- `X-Api-Ratelimit-Consumed`: credits consumed by current request
- `X-Api-Ratelimit-Remaining`: credits remaining in current window
- `X-Api-Ratelimit-Limit`: total credits for current window
- `X-Api-Ratelimit-Reset`: reset time in UTC epoch seconds

```bash
curl -i -X GET "https://api.marketdata.app/v1/stocks/quotes/AAPL/" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

## Common Cost Traps

1. Pulling full option chains without filters
2. Including `bid/ask/mid/last` unnecessarily
3. Repeating expensive live requests without caching or deduplication
4. Ignoring rate-limit headers during production runs

## Common Scenarios

### Scenario 1: "I requested one option chain and ran out of credits"

What happened:
- A single `options/chain` request returned a very large number of contracts.
- With quote fields included, credits scaled by returned contracts.

What to do:
- Free + Trials: use server-side filters or two-step local filtering; consider historical chains for bulk snapshots.
- Starter + Trader and Quant + Prime: use `mode=cached` for bulk pulls, then selectively refresh only contracts you need live.

### Scenario 2: "I made a small number of requests but used far more credits than expected"

What happened:
- Requests hit bulk endpoints (`options/chain`, `stocks/quotes`, `stocks/prices`) with quote fields.
- Credit usage scaled with symbols/contracts returned, not request count.

What to do:
- Inspect `X-Api-Ratelimit-Consumed` for high-cost requests.
- Remove unnecessary quote fields or reduce returned symbols/contracts with filters.

### Scenario 3: "My credits did not reset at midnight"

What happened:
- You expected a calendar-day reset.
- Daily-limit plans reset at **9:30 AM Eastern Time**, not midnight.

What to do:
- Use `X-Api-Ratelimit-Reset` as source of truth for exact reset timing.
- Align scheduler logic to `America/New_York` and the 9:30 AM ET window.

### Scenario 4: "I need bulk option data every day on Free/Trial"

What happened:
- No access to `mode=cached` on Free/Trial makes full quote-chain pulls expensive.

What to do:
- Use one-step server-side liquidity/contract filters or two-step local filtering.
- If intraday quote freshness is not required, prefer historical chain snapshots (`date`) for lower credit burn.
- If this remains insufficient, upgrade to a paid plan.

### Scenario 5: "I am on Starter/Trader and still getting blocked daily"

What happened:
- Cached mode is not being used as primary bulk strategy, or stale cache fallback is too broad (full live repulls).

What to do:
- Make `mode=cached` the default bulk path.
- Check `updated` freshness and only re-request live data for required contracts/symbols.
- Add daily guardrails to stop or degrade workload before hard-limit exhaustion.

## When to Contact Support

Open a support ticket if you have optimized for your plan group and still cannot operate within limits.

Include:

1. Recent `X-Api-Ratelimit-*` header values
2. Sample expensive requests
3. Your current plan
4. Expected request volume and interval
