# Simulate savings returns (GET /simulate)

Source: DepositScout Data API docs — https://depositscout.com/developers/docs/simulate

What a balance would earn in one product (sourceKey) or at a plain rate (rate): interest, end balance and the rate for each stretch, with an intro bonus ending on time and fixed rates held to the end of the term.

---

Pass rateChange to see a variable rate moving (e.g. -0.5). AER compounded annually, gross, nothing added or withdrawn; the response lists every assumption. An illustration, not advice.

- **Cost:** 2 DS Credits per request
- **Scope:** `rates:read`
- **Same data as:** the DepositScout website

## Request

`GET https://depositscout.com/api/developer/v1/simulate`

| Parameter | In | Type | Example | Description |
| --- | --- | --- | --- | --- |
| amount* | query | number | 50000 | Balance in pounds. |
| sourceKey | query | string | example-bank-easy-saver | Product from /rates. Pass this or rate. |
| rate | query | number | — | An AER to simulate instead of a product, e.g. 4.5. |
| months | query | integer | 12 | Period, 1 to 120. Defaults to a fixed product's term, otherwise 12. |
| rateChange | query | number | -0.5 | Percentage points to move variable rates by, e.g. -0.5. |

## Example

**curl**

```bash
curl "https://depositscout.com/api/developer/v1/simulate?amount=50000&sourceKey=example-bank-easy-saver&months=12&rateChange=-0.5" \
  -H "Authorization: Bearer $DS_API_KEY"
```

**Node**

```javascript
const res = await fetch("https://depositscout.com/api/developer/v1/simulate?amount=50000&sourceKey=example-bank-easy-saver&months=12&rateChange=-0.5", {
  headers: { Authorization: `Bearer ${process.env.DS_API_KEY}` },
});
const { data, meta } = await res.json();
console.log(meta.creditsCharged, data);
```

**Python**

```python
import os, requests

res = requests.get(
    "https://depositscout.com/api/developer/v1/simulate?amount=50000&sourceKey=example-bank-easy-saver&months=12&rateChange=-0.5",
    headers={"Authorization": f"Bearer {os.environ['DS_API_KEY']}"},
)
body = res.json()
print(body["meta"]["creditsCharged"], body["data"])
```

**MCP (tool call)**

```mcptoolcall
curl https://depositscout.com/api/mcp \
  -H "Authorization: Bearer $DS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"simulate","arguments":{"amount":50000,"sourceKey":"example-bank-easy-saver","months":12,"rateChange":-0.5}}}'
```

## Response

`data` is a single object. Every 2xx also sets `X-DS-Request-Id`, `X-DS-Credits-Charged`, `X-DS-Credits-Balance`, the `X-RateLimit-*` trio and an `ETag`.

```json
{
  "data": {
    "…": "the item"
  },
  "meta": {
    "requestId": "req_7f3a9c2d1b4e5a6f7c8d",
    "generatedAt": "2026-09-21T09:00:00.000Z",
    "creditsCharged": 2,
    "creditsBalance": 199,
    "attribution": "Rates powered by DepositScout — depositscout.com"
  }
}
```

## Errors

What this endpoint can return instead of data. Every error has the same shape: `error` (a stable code to branch on), `message` (what to do next), `requestId` and a `docs` link, plus the extra fields shown. None of them is charged.

401 `missing_api_key` — No Authorization header, or it isn't a Bearer token.

```json
{
  "error": "missing_api_key",
  "message": "Send your key as 'Authorization: Bearer ds_live_…'. Create one at https://depositscout.com/developer.",
  "requestId": "req_7f3a9c2d1b4e5a6f7c8d",
  "docs": "https://depositscout.com/developers/docs#missing_api_key"
}
```

403 `insufficient_scope` — The key doesn't carry the scope the endpoint needs.

```json
{
  "error": "insufficient_scope",
  "message": "This key doesn't have the 'rates:read' scope.",
  "requestId": "req_7f3a9c2d1b4e5a6f7c8d",
  "docs": "https://depositscout.com/developers/docs#insufficient_scope",
  "required": "rates:read"
}
```

402 `insufficient_credits` — Balance is lower than the call's cost. A list whose page you can't fully afford is cut to the rows your balance covers instead (meta.limit and X-DS-Limit-Reduced say so), so this only happens below one row's price. Body has required, balance and topUp.

```json
{
  "error": "insufficient_credits",
  "message": "Not enough DS Credits for this request. Top up at https://depositscout.com/developer/credits.",
  "requestId": "req_7f3a9c2d1b4e5a6f7c8d",
  "docs": "https://depositscout.com/developers/docs#insufficient_credits",
  "required": 2,
  "balance": 0,
  "topUp": "https://depositscout.com/developer/credits"
}
```

429 `rate_limited` — Burst or daily limit hit. Retry-After tells you when.

```json
{
  "error": "rate_limited",
  "message": "Too many requests. Retry after 12s.",
  "requestId": "req_7f3a9c2d1b4e5a6f7c8d",
  "docs": "https://depositscout.com/developers/docs#rate_limited",
  "retryAfter": 12
}
```

Every code is listed in the [shared error contract](https://depositscout.com/developers/docs#errors). Back to [all endpoints](https://depositscout.com/developers/docs#endpoints).
