Skip to main content

README.md

# StarlingBank

A complete, production-grade Elixir client for the
[Starling Bank Public API](https://developer.starlingbank.com/docs).

> ⚠️ Unofficial. Not affiliated with or endorsed by Starling Bank.

## Installation

```elixir
def deps do
  [
    {:starling_bank, "~> 1.0.0"}
  ]
end
```

## Configuration

```elixir
# config/runtime.exs
config :starling_bank,
  access_token: {:system, "STARLING_ACCESS_TOKEN"},
  environment: :sandbox, # or :production
  receive_timeout: 15_000,
  retry: [max_attempts: 3, base_delay_ms: 250, max_delay_ms: 4_000]
```

Or build an explicit client (recommended for multi-tenant / multi-account apps):

```elixir
client = StarlingBank.Client.new(access_token: token, environment: :production)
{:ok, accounts} = StarlingBank.Accounts.list(client)
```

## Usage

```elixir
{:ok, [account]} = StarlingBank.Accounts.list()
{:ok, balance} = StarlingBank.Balances.get(account.account_uid)

{:ok, payees} = StarlingBank.Payees.list()

{:ok, payment} =
  StarlingBank.Payments.pay_local_once(account.account_uid, account.default_category, %{
    amount: %{currency: "GBP", minorUnits: 1_000},
    reference: "Rent",
    payeeUid: payee_uid,
    payeeAccountUid: payee_account_uid
  })

{:ok, goal} =
  StarlingBank.SavingsGoals.create(account.account_uid, %{
    name: "Holiday",
    currency: "GBP",
    target: %{currency: "GBP", minorUnits: 100_000}
  })
```

Every function returns `{:ok, result} | {:error, %StarlingBank.Error{}}`.
`StarlingBank.Error` normalizes OAuth errors, `{"errors": [...]}` bodies, and
plain HTTP failures into one shape with a `reason` atom
(`:unauthorized`, `:insufficient_scope`, `:not_found`, `:rate_limited`, ...).

## Modules

| Module | Covers |
| --- | --- |
| `StarlingBank.OAuth` | authorize URL, code exchange, token refresh |
| `StarlingBank.Accounts` | accounts, identifiers, confirmation of funds |
| `StarlingBank.AccountHolders` | identity, name, address, type, email, customer |
| `StarlingBank.Balances` | cleared / effective / available balances |
| `StarlingBank.Transactions` | feed items, metadata, attachments, statements |
| `StarlingBank.Receipts` | itemized receipts + receipt attachments |
| `StarlingBank.Merchants` | merchant & merchant-location enrichment |
| `StarlingBank.Payees` | saved payees + images |
| `StarlingBank.Payments` | local, recurring & international payments, standing orders |
| `StarlingBank.DirectDebits` | Direct Debit mandates |
| `StarlingBank.SavingsGoals` | savings goals, top-ups, withdrawals, photos |
| `StarlingBank.Cards` | freeze/unfreeze, spending limits, channel controls |
| `StarlingBank.Webhooks` | listing + HMAC signature verification |
| `StarlingBank.CustomerOnboarding` | TPP customer onboarding (elevated access) |

## Telemetry

```elixir
:telemetry.attach(
  "log-starling-requests",
  [:starling_bank, :request, :stop],
  fn _event, measurements, metadata, _config ->
    Logger.info("Starling #{metadata.method} #{metadata.path} in #{measurements.duration}")
  end,
  nil
)
```

## Sandbox

Set `environment: :sandbox` to point at `https://api-sandbox.starlingbank.com`.
Starling's sandbox lets you create test customers, simulate transactions, and
test your integration end-to-end before requesting production scopes.

## Development

```
mix deps.get
mix compile
mix test
mix credo --strict
mix dialyzer
```

## License

MIT