# Data API reference

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

UK savings rates, rate history, providers, offers, cards and market data — one key, prepaid in DS Credits.

---

## Quick start

1. Create an account at [/developers/signup](https://depositscout.com/developers/signup), then a key at [/developer](https://depositscout.com/developer). Test keys (`ds_test_…`) are free and need no credits.
2. Send it as a Bearer token. Every response is `{ data, meta }`.
3. Check `meta.creditsCharged` and `meta.creditsBalance` as you go.

**curl**

```bash
curl "https://depositscout.com/api/developer/v1/rates?type=easy-access&provider=chase" \
  -H "Authorization: Bearer $DS_API_KEY"
```

**Node**

```javascript
const res = await fetch("https://depositscout.com/api/developer/v1/rates?type=easy-access&provider=chase", {
  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/rates?type=easy-access&provider=chase",
    headers={"Authorization": f"Bearer {os.environ['DS_API_KEY']}"},
)
body = res.json()
print(body["meta"]["creditsCharged"], body["data"])
```

**Google Sheets (Apps Script)**

```javascript
// Google Sheets → Extensions → Apps Script
function DS_RATES() {
  const res = UrlFetchApp.fetch("https://depositscout.com/api/developer/v1/rates?type=easy-access&provider=chase", {
    headers: { Authorization: "Bearer " + PropertiesService.getScriptProperties().getProperty("DS_API_KEY") },
  });
  const { data } = JSON.parse(res.getContentText());
  return data.map(p => [p.provider, p.accountName, p.rate]);
}
```

## Authentication

Base URL `https://depositscout.com/api/developer/v1`. Send `Authorization: Bearer ds_live_…` on every request. Keys are never accepted in the query string or in `X-API-Key`. A key is shown once when created; revoke it from the portal if it leaks. Live keys can carry an IP allow-list.

**Test mode.** `ds_test_…` keys hit the same endpoints and get the same shape, headers and pagination — but the data is a small **sample set of fictional providers**, not live rates (`meta.sample: true`, `X-DS-Sample-Data: true`). They cost nothing, are rate-limited harder (10/min) and add `X-DS-Mode: test`. Build against a test key; switch to a live key for real data — your 20 starter credits cover the first real calls.

## Credits & pricing

Requests are prepaid in **DS Credits**: £1 = 10 DS Credits. New accounts start with 20 free credits. Top up from £5 (presets £5, £20, £50, £100). Credits never expire. Each request costs the endpoint's weight below — a page of results is one request. `304 Not Modified`, validation errors, `429` and `5xx` are free.

**What live keys can call today.** While the platform is new, live keys are open on `/rates`, `/history`, `/providers`, `/switch-offers` and everything under them. The other endpoints are marked *test keys only* in the table below: test keys get sample data as normal, but a live key gets `403 endpoint_restricted` and is not charged. Their prices are shown so you can plan; email <mailto:api@depositscout.com> for early access.

Responses are shared between callers for up to 60 seconds, so a busy endpoint stays fast; each request is still charged. Cancellation and refunds: see the [refund policy](https://depositscout.com/developers/refunds).

**Counting catches up a moment later.** Usage is written a few seconds behind the calls it counts, so a request you made a second ago may not be in `/me`, the usage page or your balance yet. Nothing is lost — it settles within a few seconds. `/me` returns `usage.asOf` so you can tell what the figures are true as of, rather than assuming they are live. Charging itself is immediate: the credits for a request are taken as it is served, and `meta.creditsBalance` on that response is already up to date.

## Pagination & caching

- Lists take `?limit=` (default 10, maximum 50 — larger values are clamped and the applied value is in `meta.limit`) and `?cursor=` from `meta.nextCursor`.
- `?fields=a,b,c` trims each item to the fields you need.
- Every response carries an `ETag`. Send it back as `If-None-Match` and an unchanged result is a free `304` — this is how pollers keep costs down.
- Dates are ISO 8601 UTC; money is a two-decimal GBP string; rates are strings like `"4.42"`.

## Rate limits

60 requests per minute per live key (10 for test keys) and 5,000 per day per account across all keys. Over either limit you get `429` with `Retry-After`. Every response includes `X-RateLimit-Limit`, `-Remaining` and `-Reset`.

## Webhooks

Coming soon — this section describes how webhooks will work so you can plan for them.

Instead of polling, we can call your endpoint when something changes. Webhooks are switched on per account — ask from the [Webhooks page](https://depositscout.com/developer/webhooks) of your dashboard.

- **Events:** `rate.changed`, `product.added`, `product.withdrawn`, `switch_offer.changed`. Filter each endpoint by provider, account type or minimum rate change so you only pay for what you use.
- **Payload:** `{ id, type, createdAt, attempt, data }`, where `data` is the same shape the matching endpoint returns (a history row, a product, an offer).
- **Signature:** every request carries `X-DS-Signature: t=<unix seconds>,v1=<hex>` where `v1` is HMAC-SHA256 of `` `${t}.${rawBody}` `` with your endpoint's secret. Reject anything older than five minutes. Also sent: `X-DS-Event` and `X-DS-Delivery`.
- **Retries:** a non-2xx response or a timeout (10s) is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours, then marked dead; you can redeliver from the dashboard.
- **Pricing:** 5 DS Credits per *delivered*event (first 2xx only — retries are never charged again). Test events are free. If your balance can't cover the next delivery the endpoint pauses, not deletes, and resumes when you top up.

```javascript
import { createHmac, timingSafeEqual } from "node:crypto";

// Verify before trusting the body. Use the raw request body, not a re-serialised object.
export function verifyDepositScoutSignature(secret, signatureHeader, rawBody) {
  const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(parts.v1, "hex"));
}
```

## Endpoints

### Account

| Endpoint | Credits | Scope |
| --- | --- | --- |
| [GET /ping — Check your key works](https://depositscout.com/developers/docs/ping) | Free | any key |
| [GET /me — Your account, balance and limits](https://depositscout.com/developers/docs/me) | Free | any key |

### Rates

| Endpoint | Credits | Scope |
| --- | --- | --- |
| [GET /rates — Live UK savings rates](https://depositscout.com/developers/docs/rates) | 1 | rates:read |
| [GET /rates/{sourceKey} — One savings product](https://depositscout.com/developers/docs/rates.item) | 1 | rates:read |

### History

| Endpoint | Credits | Scope |
| --- | --- | --- |
| [GET /history — Rate change history](https://depositscout.com/developers/docs/history) | 2 | history:read |
| [GET /history/components — Base and bonus rate history](https://depositscout.com/developers/docs/history.components) | 2 | history:read |
| [GET /rate-trends — Market rate trends Test keys only](https://depositscout.com/developers/docs/rate-trends) | 5 | history:read |

### Providers

| Endpoint | Credits | Scope |
| --- | --- | --- |
| [GET /providers — Provider directory](https://depositscout.com/developers/docs/providers) | 1 | providers:read |
| [GET /providers/{slug} — One provider](https://depositscout.com/developers/docs/providers.item) | 1 | providers:read |
| [GET /providers/{slug}/service-quality — Provider service quality](https://depositscout.com/developers/docs/providers.service-quality) | 2 | providers:read |

### Offers

| Endpoint | Credits | Scope |
| --- | --- | --- |
| [GET /switch-offers — Current account switch offers](https://depositscout.com/developers/docs/switch-offers) | 1 | offers:read |
| [GET /account-offers — Current account offers Test keys only](https://depositscout.com/developers/docs/account-offers) | 5 | offers:read |

### Cards

| Endpoint | Credits | Scope |
| --- | --- | --- |
| [GET /cards/rewards — Reward credit cards Test keys only](https://depositscout.com/developers/docs/cards.rewards) | 5 | cards:read |
| [GET /cards/travel — Travel cards Test keys only](https://depositscout.com/developers/docs/cards.travel) | 5 | cards:read |
| [GET /cards/travel/fx-history — FX rate history Test keys only](https://depositscout.com/developers/docs/cards.travel.fx-history) | 5 | cards:read |

### Market

| Endpoint | Credits | Scope |
| --- | --- | --- |
| [GET /market/overview — Market overview Test keys only](https://depositscout.com/developers/docs/market.overview) | 5 | market:read |
| [GET /market/averages — Average rates Test keys only](https://depositscout.com/developers/docs/market.averages) | 5 | market:read |
| [GET /market/category-stats — Category statistics Test keys only](https://depositscout.com/developers/docs/market.category-stats) | 5 | market:read |
| [GET /market/card-stats — Card market statistics Test keys only](https://depositscout.com/developers/docs/market.card-stats) | 5 | market:read |
| [GET /market/hero-stats — Headline statistics Test keys only](https://depositscout.com/developers/docs/market.hero-stats) | 5 | market:read |
| [GET /market/boe-rate — Bank of England base rate Test keys only](https://depositscout.com/developers/docs/market.boe-rate) | 5 | market:read |
| [GET /market/ecb-rate — ECB rate Test keys only](https://depositscout.com/developers/docs/market.ecb-rate) | 5 | market:read |
| [GET /market/inflation — UK inflation Test keys only](https://depositscout.com/developers/docs/market.inflation) | 5 | market:read |

### Assistant

| Endpoint | Credits | Scope |
| --- | --- | --- |
| [POST /assistant — Ask Penny Coming soon](https://depositscout.com/developers/docs/assistant) | 10 | assistant |

## Errors

Every error is JSON with `error`, a plain-English `message` that says what to do next, `requestId` and a `docs` link. None of them cost credits.

| Status | error | When |
| --- | --- | --- |
| 400 | invalid_request | Bad query or path value, such as a malformed cursor. |
| 401 | missing_api_key | No Authorization header, or it isn't a Bearer token. |
| 401 | invalid_api_key | The key isn't one of ours or doesn't exist. |
| 402 | insufficient_credits | Balance is lower than the endpoint's cost. Body has required, balance and topUp. |
| 403 | key_revoked | The key was revoked in the portal. |
| 403 | account_blocked | The account is blocked. The body includes the reason where we can share it. |
| 403 | insufficient_scope | The key doesn't carry the scope the endpoint needs. |
| 403 | ip_not_allowed | The key has an IP allow-list and the caller isn't on it. |
| 403 | licence_reacceptance_required | The Data Licence changed and the grace period has ended. |
| 403 | email_not_verified | Portal only: verify your email before creating a live key or topping up. |
| 403 | webhooks_not_enabled | Portal only: webhooks are an admin-enabled feature. |
| 403 | sample_data_unavailable | A test key was used on an endpoint that has no sample data yet. Use a live key. |
| 403 | endpoint_restricted | A live key was used on an endpoint that is test-only for now. See the open list on the endpoints table. |
| 404 | not_found | Unknown route, unknown sourceKey or slug, or an endpoint that hasn't launched yet. |
| 429 | rate_limited | Burst or daily limit hit. Retry-After tells you when. |
| 500 | internal_error | Our fault. Quote requestId to api@depositscout.com. |

## Versioning

`/v1` shapes are frozen: we only add fields. A breaking change ships as `/v2` with a six-month overlap and `Deprecation` / `Sunset` headers, announced on the [changelog](https://depositscout.com/developers/changelog). Use of the API is under the [Data Licence v2026-09](https://depositscout.com/developers/licence).
