
7 Oct 2026 · 11 min read · Updated 7 Oct 2026

This is the hands-on one. By the end you'll have a free test key, a live call returning UK savings rates, a loop that pages through a whole account type, the same data in a Google Sheet, and an AI assistant that can query it for you. Every step has copy-paste code in curl, Node or Python, and none of it needs a card.
If you'd like the bigger picture first (what the API covers, who it's built for and how teams tend to use it), read Getting Started with the DepositScout API. The full endpoint reference lives at /developers/docs. This tutorial sits between the two: the order to do things in, and the things people trip over along the way, from pagination and credits to caching and the error codes you'll actually see.
Sign up at /developers/signup, create a ds_test_ key in the portal, and call GET https://depositscout.com/api/developer/v1/rates with Authorization: Bearer <key>. Test keys are free and return sample data. Live keys cost 1 credit per row of rates, and £1 buys 10 credits.
Go to /developers/signup and sign up with an email and password or with Google. Confirm your email, and the sign-up completes with 20 starter credits on the account and the Data Licence accepted. We review new accounts before switching on live access, so you'll get an email when the portal is ready; the portal itself is at /developer, and it's the same login as the main site.
If you're already a DepositScout customer, you can request API access from the same page and keep your existing dashboard.
In the portal, open Keys and create one. You'll choose:
ds_test_… keys are free, never charged, and return a small sample dataset so you can build against the exact response shapes. ds_live_… keys return real data and spend credits.rates:read, history:read, providers:read, offers:read, cards:read, market:read. Give a key only what it needs.403 ip_not_allowed.The full key is shown once. We store only a SHA-256 hash and the first 12 characters, so if you lose it you rotate it (which revokes the old key and issues a new one in a single step). Put it in an environment variable, never in a query string, and never in client-side code.
export DS_API_KEY="ds_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
/ping is free and tells you the key's mode. Use it in health checks.
curl "https://depositscout.com/api/developer/v1/ping" \
-H "Authorization: Bearer $DS_API_KEY"
{
"data": { "ok": true, "mode": "test", "requestId": "req_7f3a9c2d1b4e5a6f7c8d" },
"meta": {
"requestId": "req_7f3a9c2d1b4e5a6f7c8d",
"generatedAt": "2026-10-07T09:00:00.000Z",
"creditsCharged": 0,
"creditsBalance": 20,
"attribution": "Rates powered by DepositScout — depositscout.com"
}
}
/me is also free and returns your plan, balance, rate limits, today's usage and a list of every endpoint with whether this key can call it. If a call is ever refused, /me is the first place to look.
Authentication is Authorization: Bearer only. There's no X-API-Key header and no ?api_key= query parameter; both are ignored and you'll get 401 missing_api_key.
GET /rates returns every UK savings product we list. Filter with type, provider and amount, and trim the payload with fields.
curl "https://depositscout.com/api/developer/v1/rates?type=easy-access&provider=chase&amount=50000" \
-H "Authorization: Bearer $DS_API_KEY"
The same call in Node:
const res = await fetch(
"https://depositscout.com/api/developer/v1/rates?type=easy-access&provider=chase&amount=50000",
{ headers: { Authorization: `Bearer ${process.env.DS_API_KEY}` } },
);
const { data, meta } = await res.json();
console.log(meta.creditsCharged, data);
And in Python:
import os, requests
res = requests.get(
"https://depositscout.com/api/developer/v1/rates",
params={"type": "easy-access", "provider": "chase", "amount": 50000},
headers={"Authorization": f"Bearer {os.environ['DS_API_KEY']}"},
)
body = res.json()
print(body["meta"]["creditsCharged"], body["data"])
Each product in data looks like this (trimmed):
{
"sourceKey": "chase-saver",
"provider": "Chase UK",
"providerSlug": "chase",
"accountName": "Chase Saver",
"accountType": "Easy Access",
"rate": "4.50",
"baseRate": "3.25",
"boostRate": "1.25",
"boostDuration": "12 months",
"interestPaid": "Monthly",
"interestType": "Variable",
"access": "Instant",
"minBalance": 0,
"maxBalance": null,
"maxMonthlyDeposit": null,
"fscsDetails": "Protected up to £120,000 by the FSCS",
"newCustomersOnly": false,
"depositscoutUrl": "https://depositscout.com/banks/chase/chase-saver",
"matchReasons": ["Easy access", "Ranks 9th of 212 easy access accounts by AER", "Accepts a £50,000 balance", "Includes a 1.25% bonus for 12 months"],
"updatedAt": "2026-10-07T06:00:00.000Z"
}
Three fields worth knowing about. sourceKey is the stable product ID: use it for /rates/{sourceKey}, /history and /simulate, and store it rather than the name, which providers rename. matchReasons is a list of plain-English facts about why the product is in your result (its rank, the filters it matched, any bonus, FSCS cover) that an AI agent can repeat without inventing anything. And depositscoutUrl is the product's page on our site; the provider's own link is a separate call, /rates/{sourceKey}/link, so that we can track it.
Valid type values: all, easy-access, fixed-rate, notice, cash-isa, junior-isa, lifetime-isa, stocks-shares-isa, regular-saver, childrens-savings. GET /reference/account-types returns the list with descriptions if you'd rather not hard-code it.
List endpoints return 25 rows a page by default, up to 50 with limit=50. The response's meta.nextCursor is an opaque token; pass it back as cursor to get the next page, and stop when it's null. You're charged per row returned, not per page, so page size doesn't change what you pay.
async function allRates(type) {
const base = "https://depositscout.com/api/developer/v1/rates";
const headers = { Authorization: `Bearer ${process.env.DS_API_KEY}` };
let cursor = null;
const rows = [];
do {
const url = new URL(base);
url.searchParams.set("type", type);
url.searchParams.set("limit", "50");
url.searchParams.set("fields", "sourceKey,provider,accountName,rate,accountType");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, { headers });
const { data, meta } = await res.json();
rows.push(...data);
cursor = meta.nextCursor;
} while (cursor);
return rows;
}
If you only need to find a product, don't page through /rates. GET /reference/products returns every product's sourceKey, name, provider and type for one credit, however many there are. Look up the key there, then fetch the one product you want.
Pricing is per call, in DS Credits. £1 buys 10 credits, so a credit is 10p. The starter 20 credits are 20 rows of rates. Top-ups start at £5 (50 credits), with presets at £5, £20, £50 and £100, and credits don't expire.
| Endpoint | Cost |
|---|---|
/ping, /me | Free |
/reference/* (providers, products, account types, FSCS licences, currencies, cards) | 1 credit for the whole list |
/rates, /providers, /switch-offers | 1 credit per row returned |
/rates/{sourceKey}, /rates/{sourceKey}/link | 1 credit |
/calculators/savings-tax, /calculators/isa-allowance, /calculators/savings-growth, /calculators/regular-saver | 1 credit |
/simulate, /providers/{slug}/service-quality | 2 credits |
/history, /history/components | 2 credits per row (Enterprise plan) |
/assets/providers/{slug} (logo) | 5 credits |
/market/*, /rate-trends, /cards/* | 2 to 5 credits (test keys only at the moment) |
Things that are never charged: errors, validation failures, 304 Not Modified, and anything a test key does. Every response tells you what it cost and what's left in meta.creditsCharged and meta.creditsBalance, and in the X-DS-Credits-Charged and X-DS-Credits-Balance headers.
If your balance can't cover a full page, you don't get an error: the page is cut to the rows you can afford, meta.limit shows the reduced count and the response carries X-DS-Limit-Reduced. You only see 402 insufficient_credits when you can't afford a single row, and the body tells you the balance, what was required and where to top up. Provider logos inside product responses are an Enterprise-plan feature; on other plans the providerLogoUrl field is omitted and you fetch a logo from /assets/providers/{slug} instead.
Limits depend on the plan. Hobby (the default) is 60 requests a minute and 1,000 a day on live keys; Business is 300 a minute and 20,000 a day; Enterprise is 600 a minute and 100,000 a day. Test keys get 10 a minute. Hit a limit and you get 429 rate_limited with a Retry-After header. Daily caps are per account, so two keys share one allowance.
Responses are cached on our side for about a minute, so hammering /rates every few seconds won't get you fresher data and will spend credits. Rates on the site update daily, with most provider changes landing in the morning. For anything you display, polling every 15 to 60 minutes is plenty.
Use ETags. Every response carries an ETag; send it back as If-None-Match and if nothing has changed you get a 304 with no body and no charge. For a dashboard that refreshes often, this is the single biggest saving available.
curl -i "https://depositscout.com/api/developer/v1/rates?type=cash-isa&limit=10" \
-H "Authorization: Bearer $DS_API_KEY" \
-H 'If-None-Match: "the-etag-from-last-time"'
Errors are JSON with a stable code, a message and the requestId. The ones that matter in practice:
| Status | Code | What it means |
|---|---|---|
| 401 | missing_api_key / invalid_api_key | No Bearer header, or the key isn't one of ours. Check the environment variable made it into the process. |
| 403 | insufficient_scope | The key doesn't have the scope for that endpoint. Create a key with the right scopes rather than widening an existing one. |
| 403 | endpoint_restricted | A live key on an endpoint that's test-only for now (the market and cards groups). Use a test key or wait for it to open. |
| 403 | plan_upgrade_required | A live key on an endpoint your plan doesn't include (rate history is Enterprise). Not charged; the body names the plan you'd need. |
| 402 | insufficient_credits | Balance below the price of one row. Top up at /developer/credits. |
| 429 | rate_limited | Back off for Retry-After seconds. |
| 400 | invalid_request | Usually a cursor that's been mangled or reused across different queries. |
| 404 | not_found | Unknown sourceKey or provider slug. Look it up in /reference/products or /reference/providers. |
If you get a 500 internal_error, email [email protected] with the requestId and we'll find it in the logs.
A surprising number of people want the rates in a spreadsheet, not an app. Extensions → Apps Script, paste this, store your key in Script Properties as DS_API_KEY, then type =DS_RATES() in a cell.
function DS_RATES() {
const res = UrlFetchApp.fetch("https://depositscout.com/api/developer/v1/rates?type=easy-access&limit=50", {
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]);
}
Every endpoint is also exposed as a tool on our MCP server at https://depositscout.com/api/mcp, using the same key and the same prices. Point Claude Desktop, Cursor or your own agent at it and it can ask for "the best easy access rate for £50,000" and get back products with matchReasons it can cite. Setup instructions for each client are at /developers/ai-agents. The same call as a raw MCP request:
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":"rates","arguments":{"type":"easy-access","amount":50000,"limit":3}}}'
/rates?type=easy-access&amount=X, sort by rate, show the top three with matchReasons./rates/{sourceKey} for the accounts you care about and diff rate; or ask us about webhooks, which are enabled per account and cost 5 credits a delivery./simulate takes a sourceKey (or a plain rate), a balance and a number of months and returns the interest and end balance using the product's actual terms, with any intro bonus ending on time and fixed rates held to maturity. For drip-feed accounts, /calculators/regular-saver takes monthly, rate and months and does the interest-on-each-deposit maths properly./reference/fscs returns every brand we track with its banking licence and the other brands sharing the limit, for one credit./calculators/savings-tax takes income and interest and returns what's owed under the personal savings allowance rules.The OpenAPI 3.1 document is at /api/developer/openapi.json and a Postman collection at /api/developer/postman.json; both are generated from the same catalogue as the docs, so they can't drift. Changes to endpoints or pricing are posted at /developers/changelog. The Data Licence, which covers attribution and what you can and can't do with the data, is at /developers/licence; every response carries the attribution string in meta.attribution so you've always got it to hand.
Test keys are free and unlimited in credits (rate-limited to 10 requests a minute) but return sample data. Live data costs credits: 1 credit, or 10p, per row of rates. New accounts get 20 credits free.
Products are checked against provider websites daily, with most changes landing in the morning UK time. updatedAt on each product tells you when it last changed. Responses are cached for about a minute.
Yes, within the Data Licence you accept at sign-up. Attribution requirements and restrictions on redistribution are set out there.
Only for rate history (/history, /history/components) and for logos embedded in product responses. Everything else in the live families is available on the Hobby plan with a live key.
The legacy partner API at /api/v1 still works for existing partners with keys. New integrations should use /api/developer/v1, which has the consistent { data, meta } envelope, cursor pagination, per-row pricing, scopes, test keys and MCP.
[email protected] with the requestId from meta for API problems. For a rate that looks wrong, the product's depositscoutUrl page has a "report an issue" link.
Request access, learn the four core feeds, and make your first call to live UK savings data.
Power fintech apps and AI assistants with structured UK savings rates, history and provider data.
Keep best-buy tables accurate with live UK savings rates — without scraping bank sites every morning.
Tell us what you're building and we'll get back to you about API access and commercial licensing.
[email protected]