starlingbank/api-samples: The sample repo that turns bank APIs into a cryptographic contract

How Starling teaches developers to sign requests, verify webhooks, and move between public banking APIs and payment services without guessing at the rules.

10 min read • View on GitHub • More from starlingbank

A wide black-ink scene shows several hands at different language workbenches stamping the same bank request form before it passes through a vault door. It explains that the repo's real job is deterministic signing, not generic sample code.
The surprise is not that Starling shows you how to call an API. It is that it shows you how the same request becomes the same signed object in every supported language.
Key Takeaways

The real job of this repo

Most sample repos teach you where to paste a token. Starling's teaches you how the same request becomes the same signed object in Java, Python, Go, C#, and JavaScript. That matters because in banking, a one character drift is not a formatting bug. It is an auth failure.

That is why starlingbank/api-samples reads more like a reference implementation than a demo zoo. The repo is split around banking work, not framework fashion, and the language ports exist to prove parity, not to show off syntax.

A split workshop scene shows public API examples on one bench, payment services flows on another, and a shared tools shelf in the middle. It explains that the repository is organized by banking task, not by language or framework.
The directory layout mirrors the product surface. Public API, Payment Services API, and shared concerns each get their own lane.

The Java code carries the most weight, but the repo is not Java only. It includes examples in C#, JavaScript, Python, and Go, plus both Gradle and Maven build files, which is a quiet signal that these samples are meant to be copyable into real enterprise stacks, not admired from a distance.

Our public API will allow the best innovations to reach our customers in a fast, accessible way. We’re thrilled to be launching our platform and anticipate that some great ideas to help customers will come of our first Hackathon using the open API.

Anne Boden, CEO & founder at Starling Bank · Finextra launch story

That open API pitch is the backdrop here. Starling was not only exposing endpoints, it was inviting developers to build on top of the bank without guessing what the platform meant by trust, signing, and verification.

Inside the signature pipeline

The technical center of gravity lives in StarlingMessageSigner.java and SignatureUtils.java. The pipeline is straightforward to describe and easy to get wrong: hash the payload, build a canonical string from (request-target), Date, and Digest, then sign that string and place the result into an Authorization header.

A signing bug can live in a method case, a newline, or a body hash. The diagram shows where the pipeline diverges, and why the repo keeps every step explicit.

Bearer %s;Signature keyid="%s",algorithm="%s",headers="(request-target) Date Digest",signature="%s"

The brittle part is not cryptography in the abstract. It is the formatting. Lowercase the method where the spec expects lowercase. Preserve line breaks. Keep the body encoding stable. Change any of those and two implementations that look equivalent will produce different outputs.

That is why the repo carries ports in several languages. It is less about teaching syntax than proving that one canonical interpretation survives across runtimes. In a payment flow, reproducibility is the product.

Public API versus Payment Services API

The split is not cosmetic. Starling is serving two different developer jobs, and the repository mirrors that division.

FeaturePublic APIPayment Services API
Intended userRetail or SME developer automating a personal or business accountPartner or institution integrating banking infrastructure
Core operationRead balances, move money, validate webhooksIssue accounts, instruct payments, manage key material
Trust modelBearer token plus signed requests for sensitive callsPartner-grade setup with generated keys and payment instructions
ComplexityLower, but still precise about signing and verificationHigher, because onboarding and signing are part of the workflow
Why the samples existShow the smallest correct path to common account tasksShow the full lifecycle from key generation to payment instruction
A wide split-screen scene contrasts a developer-facing account console on the left with a more industrial payment infrastructure on the right. It explains that the two API surfaces serve different users and trust models.
Public API and Payment Services API are not just different endpoint sets. They sit at different points on the trust ladder.

If the public API feels like a developer-facing control panel, the Payment Services side feels like infrastructure. That difference matters because the repo is teaching trust boundaries, not just endpoint names.

Webhook security flips the direction of trust

Outbound requests are only half the story. When Starling calls you back, the verification problem reverses, and StarlingV2WebhookSignatureValidator.java shows the bank authenticating itself to your system with a public key signature. The repo's common-examples/key-rotation sample makes the lifecycle explicit: keys are not static souvenirs, they are managed assets.

A parcel arrives at a receiving desk with a wax-like seal inspected against a public key stamp, while a second parcel with a broken seal is pushed aside. It explains webhook verification as asymmetric trust.
The webhook flow is the mirror image of request signing. Your system verifies the sender before it trusts the payload.

That is the important mental model shift. Shared secrets ask both sides to know the same thing. Asymmetric verification lets your system prove the sender owns the private key without ever learning it. In other words, the repo is not just teaching developers to send money, it is teaching them to trust money-moving messages in both directions.

Why this samples repo matters

Good samples shrink product ambiguity. In this case, the samples do more than lower onboarding friction. They function like a specification written in code, which is exactly what banking integrations need when correctness, not novelty, is the goal.