DepositScout API Tutorial with Code Examples

DepositScout API Tutorial with Code Examples

JJonny Pease

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

Copy-paste code to pull live UK savings rates into Node, Python and Google Sheets.

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.

Step 1: Create a developer account

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.

Step 2: Create a key

In the portal, open Keys and create one. You'll choose:

  • Mode. 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.
  • Scopes. Which families of endpoint the key can call: rates:read, history:read, providers:read, offers:read, cards:read, market:read. Give a key only what it needs.
  • IP allow-list (optional). Up to 20 addresses or ranges. Calls from anywhere else get 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"

Step 3: Check the key works

/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.

Step 4: Your first real call: live rates

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.

Step 5: Pagination

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.

Step 6: Understand credits before you spend them

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.

EndpointCost
/ping, /meFree
/reference/* (providers, products, account types, FSCS licences, currencies, cards)1 credit for the whole list
/rates, /providers, /switch-offers1 credit per row returned
/rates/{sourceKey}, /rates/{sourceKey}/link1 credit
/calculators/savings-tax, /calculators/isa-allowance, /calculators/savings-growth, /calculators/regular-saver1 credit
/simulate, /providers/{slug}/service-quality2 credits
/history, /history/components2 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.

Step 7: Rate limits and caching

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"'

Step 8: Handle the errors you'll actually see

Errors are JSON with a stable code, a message and the requestId. The ones that matter in practice:

StatusCodeWhat it means
401missing_api_key / invalid_api_keyNo Bearer header, or the key isn't one of ours. Check the environment variable made it into the process.
403insufficient_scopeThe key doesn't have the scope for that endpoint. Create a key with the right scopes rather than widening an existing one.
403endpoint_restrictedA 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.
403plan_upgrade_requiredA live key on an endpoint your plan doesn't include (rate history is Enterprise). Not charged; the body names the plan you'd need.
402insufficient_creditsBalance below the price of one row. Top up at /developer/credits.
429rate_limitedBack off for Retry-After seconds.
400invalid_requestUsually a cursor that's been mangled or reused across different queries.
404not_foundUnknown 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.

Google Sheets in five lines

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]);
}

Using the API from Claude, Cursor or any MCP client

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}}}'

What to build next

  • A "best rate for me" widget: /rates?type=easy-access&amount=X, sort by rate, show the top three with matchReasons.
  • Rate-change alerts: poll /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.
  • "How much would I earn" calculators: /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.
  • FSCS checks: /reference/fscs returns every brand we track with its banking licence and the other brands sharing the limit, for one credit.
  • Tax: /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.

Frequently asked questions

Is the DepositScout API free?

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.

How often is the data updated?

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.

Can I use the data commercially?

Yes, within the Data Licence you accept at sign-up. Attribution requirements and restrictions on redistribution are set out there.

Do I need the Enterprise plan?

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.

What's the difference between this and the old /api/v1?

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.

Where do I report a bug or a wrong rate?

[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.

Related Topics

api
developer
tutorial
code examples
node
python
google sheets
mcp
rates api

Request API access

Tell us what you're building and we'll get back to you about API access and commercial licensing.

[email protected]

We'll only use these details to respond to your API access enquiry.