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.
- Starling's samples repo is a deterministic signing reference, not a generic starter kit.
- Its folder structure mirrors banking workflows, separating public API, payment services, and shared key rotation.
- The hardest lesson is that tiny formatting details decide whether signatures verify across languages.
- Webhook verification completes the trust loop by proving Starling's identity back to the client.
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.
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.
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.
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.
| Feature | Public API | Payment Services API |
|---|---|---|
| Intended user | Retail or SME developer automating a personal or business account | Partner or institution integrating banking infrastructure |
| Core operation | Read balances, move money, validate webhooks | Issue accounts, instruct payments, manage key material |
| Trust model | Bearer token plus signed requests for sensitive calls | Partner-grade setup with generated keys and payment instructions |
| Complexity | Lower, but still precise about signing and verification | Higher, because onboarding and signing are part of the workflow |
| Why the samples exist | Show the smallest correct path to common account tasks | Show the full lifecycle from key generation to payment instruction |
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.
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.